使用springboot+EasyExcel+Layui实现批量数据导入导出

news/2024/4/23 14:40:07/文章来源:https://blog.csdn.net/l_zl2021/article/details/129167918

文章目录

  • 前言
  • 一、导入依赖
  • 二、配置监听器
  • 三、controller编写
  • 四、Service业务层
  • 五、持久层不再赘述
  • 六、前端
  • 总结


前言

之前出过一期easyExcel在SSM的环境下使用流程,本篇演示在springboot环境下easyExcel的使用
上篇链接
使用EasyExcel实现表格的导入导出【http://t.csdn.cn/0MLgt】


一、导入依赖

 <!-- easyexcel依赖--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></dependency>

二、配置监听器

package com.lzl.idpac.listener;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.lzl.idpac.entity.Student;
import com.lzl.idpac.entity.StudentExcel;
import com.lzl.idpac.service.StudentService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;/*** --效率,是成功的核心关键--* 学生信息管理导入excel表格监听器** @Author lzl* @Date 2023/1/30 21:05*/
@Component
@Scope("prototype")//标记此处的监听器为多例的,防止并发读操作时出现错误
public class StudentReadListener implements ReadListener<StudentExcel> {@Autowiredprivate StudentService service;//注入学生管理业务层接口@Overridepublic void invoke(StudentExcel studentExcel, AnalysisContext analysisContext) {//每读取一行,就调用一次,把每一行数据封装到实体类中Student student = new Student();BeanUtils.copyProperties(studentExcel,student);//属性不一致时使用属性拷贝//导入之前做一个去重判断Integer key =  service.findBySno(student.getStuNo());if(key != 1 ){//数据库中没有该学号service.addNew(student);//调用新增方法}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {//数据解析完毕执行方法}
}

三、controller编写

package com.lzl.idpac.controller;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.lzl.idpac.entity.Student;
import com.lzl.idpac.entity.StudentExcel;
import com.lzl.idpac.listener.StudentReadListener;
import com.lzl.idpac.service.StudentService;
import com.lzl.idpac.utils.LayUiUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;/*** --效率,是成功的核心关键--* excel表格上传控制层** @Author lzl* @Date 2023/1/30 21:18*/
@RestController
@RequestMapping("/excel")
public class ExcelController {@Autowiredprivate StudentReadListener listener;//注入监听器@Autowiredprivate StudentService service;//注入学生管理业务层/***excel数据写入数据库* @param file 获得前端上传的文件  EasyExcel.read 需要传入三个参数 文件流 操作实体类的字节码 监听器* @return 0 成功上传* @throws IOException*/@RequestMapping("/read")@ResponseBodypublic LayUiUtil<String> readExcel(MultipartFile file) throws IOException {      // 得到excel读取对象  //通过文件获得流, 获得读取文件的class    填入监听器 监听器每读取一行就执行一次新增ExcelReaderBuilder read = EasyExcel.read(file.getInputStream(), StudentExcel.class, listener);//获取表格ExcelReaderSheetBuilder sheet = read.sheet();//读取表格sheet.doRead();//设置容器LayUiUtil<String> layUiUtil = new LayUiUtil<>();//配置前端响应状态码layUiUtil.setCode(0);//配置服务器返回信息layUiUtil.setMsg("已成功导入");return layUiUtil;}/*** 导出选中的数据到excel表格* @param stuNos* @param stuCollegeNo* @param response* @throws IOException*/@RequestMapping("/write")public void writeExcel(String stuNos,String stuCollegeNo, HttpServletResponse response) throws IOException {//设置响应头response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");//导出的文件名String filename = URLEncoder.encode("学生信息","utf-8");//设置响应头response.setHeader("Content-Disposition","attachment;filename="+filename+".xlsx");//获得流对象ServletOutputStream outputStream = response.getOutputStream();//获得write对象ExcelWriterBuilder write = EasyExcel.write(outputStream, StudentExcel.class);//获得数据表对象ExcelWriterSheetBuilder sheet = write.sheet();//准备需要输出的数据List<StudentExcel> list = service.getExcelDataByNos(stuNos,stuCollegeNo);//生成表格文件sheet.doWrite(list);}
}

进行导入操作时,也可以不配置监听器,通过匿名内部类实现,代码如下:

    private StudentService service;//注入学生管理业务层/***excel数据写入数据库* @param file 获得前端上传的文件  EasyExcel.read 需要传入三个参数 文件流 操作实体类的字节码 监听器* @return 0 成功上传* @throws IOException*/@RequestMapping("/read")@ResponseBodypublic LayUiUtil<String> readExcel(MultipartFile file,String stuCollegeNo) throws IOException {//匿名内部类EasyExcel.read(file.getInputStream(), StudentExcel.class, new ReadListener<StudentExcel>() {/*** 单次缓存的数据量*/public static final int BATCH_COUNT = 100;/***临时存储*/private List<StudentExcel> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);@Overridepublic void invoke(StudentExcel data, AnalysisContext context) {cachedDataList.add(data);if (cachedDataList.size() >= BATCH_COUNT) {saveData();//调用存储数据// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}/*** 读取完之后执行的方法* @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {saveData();}/*** 加上存储数据库*/private void saveData() {for(StudentExcel studentExcel : cachedDataList) {Student student = new Student();if(service.findBySno(studentExcel.getStuNo()) != 1){BeanUtils.copyProperties(studentExcel,student);student.setStuCollegeNo(stuCollegeNo);service.addNew(student);}}}}).sheet().doRead();
//第二种方法,采用监听器操作
//        // 得到excel读取对象  //通过文件获得流, 获得读取文件的class    填入监听器 监听器每读取一行就执行一次新增
//        ExcelReaderBuilder read = EasyExcel.read(file.getInputStream(), StudentExcel.class, listener);
//        //获取表格
//        ExcelReaderSheetBuilder sheet = read.sheet();
//        //读取表格
//        sheet.doRead();//设置容器LayUiUtil<String> layUiUtil = new LayUiUtil<>();//配置前端响应状态码layUiUtil.setCode(0);//配置服务器返回信息layUiUtil.setMsg("已成功导入");return layUiUtil;}

匿名内部类的方法虽然不如监听器那么简洁,但是可以让我们在controller层传入一些额外的参数,做一些别的操作。使用监听器显然是无法传入的。例如在本业务中,我在新增学生,需要同步给学生加一个学院id的属性,使用监听器无法传入学院id,但是使用匿名内部类却可以直接使用这个学院id。真实开发中这些业务逻辑还是要放在service层,此处只是学习之用,就无所谓了

四、Service业务层

接口

    /*** 根据学号,获取需要导出的数据* @param stuNos 学号字串* @return layui工具类 泛型StudentExcel*/List<StudentExcel> getExcelDataByNos(String stuNos,String stuCollegeNo);/*** 根据学号获得学生信息,用于导入去重判断* @param stuNo* @return 受影响行数*/Integer findBySno(String stuNo);/***新增学生信息* @param student 学生实体* @return layui工具类 泛型Student*/LayUiUtil<Student> addNew(Student student);

业务实现

    /*** 根据学号,获取需要导出的数据** @param stuNos* @return*/@Overridepublic List<StudentExcel> getExcelDataByNos(String stuNos,String stuCollegeNo) {//设置一个数组,存放需要导出的学号ArrayList<String> params = new ArrayList<>();if(stuNos != null && !stuNos.equals("")){//判断前端是否传递了学号String[] strList =  stuNos.split(",");//将需要导出数据的学号遍历添加进集合for (String s : strList) {params.add(s);}}//创建一个集合用来存放数据List<Student> list = new ArrayList<Student>();if(params.size()==0){//如果前端没有传递学号,即为下载模板操作,需要捏造一个测试数据list.add(new Student("202150915100","张三","男",18,"4102222000xxxxxxxx",null,"计算机科学与技术2001","慧苑1号楼101","138xxxxxxx9",null));}else {//如果前端传了学号,则为导出操作,执行持久层,获取需要导出的数据list = mapper.getStudentByStuNo(params);}//使用Lambda表达式把employee转换成employeeBoList<StudentExcel> collect = list.stream().map((student)->{StudentExcel studentExcel = new StudentExcel();BeanUtils.copyProperties(student,studentExcel);return studentExcel;}).collect(Collectors.toList());return collect;}/*** 根据学号获得学生信息,用于导入去重判断** @param stuNo* @return 受影响行数*/@Overridepublic Integer findBySno(String stuNo) {return mapper.findStudentByNo(stuNo);}/*** 新增学生信息实现类* @param student* @return*/@Overridepublic LayUiUtil<Student> addNew(Student student) {LayUiUtil<Student> layUiUtil = new LayUiUtil<>();String IDcard = student.getStuIDcard();//获取身份证号码int nums = IDcard.length()-6;//获取需要截取字串的下标位置String password = student.getStuIDcard().substring(nums);//对字串进行切割获得密码student.setStuPassword(password);//设置进实体类Integer key = mapper.addNew(student);if (key != 0){layUiUtil.setCode(1);layUiUtil.setMsg("新增成功!");}else{layUiUtil.setCode(0);layUiUtil.setMsg("新增失败!");}return layUiUtil;}

五、持久层不再赘述

六、前端

<!-- 上传excel表格 区域--><div class="layui-form-item" id="import" style="display:none;"><form class="layui-form" onsubmit="return false;" id="readExcel"><div class="layui-form-item"><label class="layui-form-label"></label><div class="layui-input-block"><div class="layui-upload"><button type="button" class="layui-btn" id="test1">上传文件</button><div style="width: 95px;"><div class="layui-progress layui-progress-big" lay-showpercent="yes" lay-filter="demo"><div class="layui-progress-bar" lay-percent=""></div></div></div></div></div></div></form></div><script type="text/javascript" src="../lib/layui-v2.6.3/layui.js"></script>
<script src="/static/js/jquery-1.12.4.min.js"></script>
<script type="text/javascript">layui.use(['table', 'layer', 'form', 'transfer','upload','element'], function () {//常规使用 - excel表格上传upload.render({elem: '#test1',accept: 'file' //普通文件,exts: 'xlsx' //上传文件格式, url: 'http://localhost:8080/excel/read' ,data: {stuCollegeNo: $userCollegeNo} //可选项。额外的参数,如:{id: 123, abc: 'xxx'}, done: function (res) {console.log(res);//如果上传失败if (res.code > 0) {layer.msg('上传失败');} else {active.reload();layer.msg(res.msg, {icon: 6,time: 1500 //2秒关闭(如果不配置,默认是3秒)}, function () {//关闭弹出层layer.closeAll();element.progress('demo', '0%'); //进度条复位});}}//进度条, progress: function (n, elem, e) {element.progress('demo', n + '%'); //可配合 layui 进度条元素使用if (n == 100) {//layer.msg('上传完毕', { icon: 1 });}}});});</script>

总结

springboot环境下,和SSM下使用EasyExcel导入和导出最大的区别是,springboot环境下不需要配置配置上传组件,因为springboot是去配置化开发,相比之下,springboot比SSM要好用的多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_72710.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

量化交易-单因子分析-alphalens

1. 数据准备 1.1 计算因子IC重要函数 def get_clean_factor_and_forward_returns(factor,prices,groupbyNone,binning_by_groupFalse,quantiles5,binsNone,periods(1, 5, 10),filter_zscore20,groupby_labelsNone,max_loss0.35,zero_awareFalse,cumulative_returnsTrue)facto…

【C语言】-程序编译的环境和预处理详解-让你轻松理解程序是怎么运行的!!

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 程序的编译前言一、 程序的翻译环境和执行环境二、 详解翻译环境2.1编译环境2.1.1预编…

民锋国际期货:2023,既艰难又充满希望,既纷乱又有无数机会。

不管是官方还是民间&#xff0c;各种信号都表明&#xff0c;2023年是一个拼经济的年份。 通货膨胀带来的需求量的增加&#xff0c;与中国经济高速发展带来的供给量增加&#xff0c;二者共同构成了我们的物价。 做一个长期主义者&#xff0c;做一个坚定看好中国未来的人&#…

MapBox动态气泡图渲染教程

先来看效果: 视频效果: 屏幕录制2023-02-22 15.34.57 首先我们来介绍一下思路。对于mapbox和openlayers这样的框架来讲,气泡图中的气泡本质上就是一个div,就是将一个dom元素追加到canvas上的固定位置而已。 在mapbox中有marker的概念,官网也有示例: Attach a popup to …

二叉树——路径总和

路径总和 链接 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点…

数据库及缓存之MySQL(一)

思维导图 常见知识点 1.mysql存储引擎&#xff1a; 2.innodb与myisam区别&#xff1a; 3.表设计字段选择&#xff1a; 4.mysql的varchar(M)最多存储数据&#xff1a; 5.事务基本特性&#xff1a; 6.事务并发引发问题&#xff1a; 7.mysql索引&#xff1a; 8.三星索引&#xf…

升职加薪必备,2023年程序员不能不知道的AI辅助编码工具

已经有很多人把chatGPT当做必备的Bug修复工具了&#xff0c;对于用AI写代码&#xff0c;有人感到失落&#xff0c;害怕被取代&#xff0c;而另一些人则认为人工智能将加快编写更好代码的过程。 尽管 AI 编写的代码并非完美无缺&#xff0c;但我相信&#xff0c;最终AI将取代人…

车机开发—【CarService启动流程】

汽车架构&#xff1a;车载HAL是汽车与车辆网络服务之间的接口定义&#xff08;同时保护传入的数据&#xff09;&#xff1a; 车载HAL与Android Automotive架构&#xff1a; Car App&#xff1a;包括OEM和第三方开发的AppCar API&#xff1a;内有包含CarSensorManager在内的AP…

Hadoop集群模式安装(Cluster mode)

1、Hadoop源码编译 安装包、源码包下载地址 Index of /dist/hadoop/common/hadoop-3.3.0为什么要重新编译Hadoop源码? 匹配不同操作系统本地库环境&#xff0c;Hadoop某些操作比如压缩、IO需要调用系统本地库&#xff08;*.so|*.dll&#xff09; 修改源码、重构源码 如何…

H12-831题库(有详细的解析)

1.&#xff08;单选&#xff09;某工程师利用2台路由器进行IPv6业务测试,通过运行BGP4模拟总部与分支的互联互通。如图所示,某工程师抓包查看R1发出的update报文。关于该报文信息的描述,以下哪个说法是正确的? A.该报文描述的路由的下一跳地址为:2001:db8::2345:1::1 B.该报文…

自动增长配置不合理导致的性能抖动

背景客户收到了SQL专家云告警邮件&#xff0c;在凌晨2点到3点之间带有资源等待的会话数暴增&#xff0c;请我们协助分析。现象登录SQL专家云&#xff0c;进入活动会话的趋势分析页面&#xff0c;下钻到2点钟一个小时内的数据&#xff0c;看到每分钟的等待数都在100左右&#xf…

关于upstream的八种回调方法

1 creat_request调用背景&#xff1a;用于创建自己模板与第三方服务器的第一次连接步骤1&#xff09; 在Nginx主循环&#xff08;ngx_worker_process_cycle方法&#xff09; 中&#xff0c;会定期地调用事件模块&#xff0c; 以检查是否有网络事件发生。2&#xff09; 事件模块…

人员行为识别系统 TensorFlow

人员行为识别系统人员行为识别系统通过TensorFlow深度学习技术&#xff0c;人员行为识别算法对画面中区域人员不按要求穿戴、违规抽烟打电话、睡岗离岗以及作业流程不规范实时分析预警&#xff0c;发现违规行为立即抓拍告警。深度学习应用到实际问题中&#xff0c;一个非常棘手…

快速读懂网络拓扑图

快速读懂网络拓扑图几重常见的网络拓扑总线型拓扑简介优点缺点环型拓扑简介优点缺点星型拓扑简介优点缺点网络层级机构节点结点链路通路不同的连接线代表什么意思&#xff1f;不同颜色、粗细的直线代表什么意思&#xff1f;闪电线-串行链路几重常见的网络拓扑 总线型拓扑 简介…

浅谈volatile关键字

文章目录1.保证内存可见性2.可见性验证3.原子性验证4.原子性问题解决5.禁止指令重排序6.JMM谈谈你的理解6.1.基本概念6.2.JMM同步规定6.2.1.可见性6.2.2.原子性6.2.3.有序性6.3.Volatile针对指令重排做了啥7.你在哪些地方用过Volatile&#xff1f;volatile是Java提供的轻量级的…

【华为OD机试模拟题】用 C++ 实现 - 求字符串中所有整数的最小和

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

【Git】Git的分支操作

目录 4、 Git 分支操作 4.1 什么是分支 4.2 分支的好处 4.3 分支的操作 4、 Git 分支操作 4.1 什么是分支 在版本控制过程中&#xff0c; 同时推进多个任务&#xff0c; 为每个任务&#xff0c; 我们就可以创建每个任务的单独分支。 使用分支意味着程序员可以把自己的工作…

postgres 源码解析50 LWLock轻量锁--1

简介 postgres LWLock&#xff08;轻量级锁&#xff09;是由SpinLock实现&#xff0c;主要提供对共享存储器的数据结构的互斥访问。LWLock有两种锁模式&#xff0c;一种为排他模式&#xff0c;另一种是共享模式&#xff0c;如果想要读取共享内存中的内容&#xff0c;需要在读取…

面试之设计模式(简单工厂模式)

案例 在面试时&#xff0c;面试官让你通过面对对象语言&#xff0c;用Java实现计算器控制台程序&#xff0c;要求输入两个数和运算符号&#xff0c;得出结果。大家可能想到是如下&#xff1a; public static void main(String[] args) {Scanner scanner new Scanner(System.…

BERT模型系列大全解读

前言 本文讲解的BERT系列模型主要是自编码语言模型-AE LM&#xff08;AutoEncoder Language Model&#xff09;&#xff1a;通过在输入X中随机掩码&#xff08;mask&#xff09;一部分单词&#xff0c;然后预训练的主要任务之一就是根据上下文单词来预测这些单词&#xff0c;从…