实现EasyExcel的导入导出(浏览器下载)

实现三个按钮的功能,但是却花费了一天的时间包括总结。

使用到的技术:springboot layui axios EasyExcel mybatis-plus

上传模板

不需要用到后端的交互,只需要前段<a>即可

<a href="../static/excel/用户信息上传模板.xlsx" style="color:white">上传模版</a>

参考链接:

Excel如何对某一列设置下拉选择项 https://jingyan.baidu.com/article/f7ff0bfccae0e62e26bb1380.html

下载上传模板 https://www.bilibili.com/video/BV1dQ4y1A75e?from=search&seid=16041556233389040505

导入数据

使用到EasyExcel的读Excel

后端

引入pom.xml 依赖

		<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>

对象

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDataExcel { @ExcelProperty("用户名")
private String userName;
@ExcelProperty("密码")
private String password;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("联系方式")
private String phone;
@ExcelProperty("用户类型")
private String typeStr;//取得的名字和User不一样,否则BeanUtils.copyProperties报错
@ExcelProperty("备注")
private String remark;
}

监听器

public class UserDataExcelListener extends AnalysisEventListener<UserDataExcel> {
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<User> list = new ArrayList<>();
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/ private UserService userService; public UserDataExcelListener() { }
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*/
public UserDataExcelListener(UserService userService ) {
this.userService = userService;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
//一行行读取
@Override
public void invoke(UserDataExcel data, AnalysisContext context) {
if(data==null){
throw new DormitoryException(ResultCode.ERROR,"文件数据为空");
}
//进行数据的转换 第一个参数复制到第二个参数中
User user = new User();
BeanUtils.copyProperties(data,user);
if(!StringUtils.isEmpty(data.getTypeStr())){
switch (data.getTypeStr()){
case "管理员":
user.setType(0);
break;
case "宿管员":
user.setType(1);
break;
case "学生":
user.setType(2);
break;
}
}
System.out.println("将excel的data复制到user,user:"+user);
list.add(user);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
}
/**
* 加上存储数据库 在监听器中直接添加
*/
private void saveData() { userService.saveBatch(list); }
}

UserController 控制层

@PostMapping("addUsers")
public Result addUsers(@RequestParam("uploadFile") MultipartFile file) throws IOException {
if(file==null){
System.out.println("文件为空");
}
boolean save = userService.addUsers(file);
return save ? Result.ok().mesaage("新增用户成功"):Result.error().mesaage("新增用户失败");
}

UserServiceImpl 业务实现层

需要注意的点,因为监听器没有Spring进行管理,所以这边的处理方式是将UserService 传入进去

@Override
public boolean addUsers(MultipartFile file) {
try{
InputStream in = file.getInputStream();
EasyExcel.read(in, UserDataExcel.class, new UserDataExcelListener(this)).sheet().doRead();
}catch (Exception e){
e.printStackTrace();
}
return true;
}

经过上面的步骤后,我们就可以先在apipost中测试接口

apipost测试MultipartFile 下面有几个注意点需要注意

前端

<button class="layui-btn  layui-btn-sm " lay-event="importData" style="background: #2ecc71" > 导入数据 </button>

使用到了layui的上传组件,由于使用到axios,也简单地修改了一下upload的源码中的axios

upload.render({
elem:'#importExcel',
url:'/user/addUsers',
size : '5000',//文件最大可允许上传的大小,单位 KB
accept:'file',//允许上传文件
exts:'xls|xlsx|xlsm|xlt|xltx|xltm',
field:'uploadFile',
headers: {token: store.getToken()},
done:function (result) {//执行上传请求后的回调。返回三个参数,分别为:res(服务端响应信息)、index(当前文件的索引)、upload(重新上传的方法,一般在文件上传失败后使用)
console.log(result);
if(result.code==0){
layer.msg("Excel导入数据成功",{ },function () {
table.reload("user-table-id");
})
}else{
layer.msg("Excel导入数据失败",function () { })
}
}
});

小插曲的Bug,写在下面这篇博客中。

layui在toolbar使用上传控件在reload后失效的问题解决

参考链接 :

java+layui实现Excel的导入导出 https://www.cnblogs.com/bbllw/p/10800161.html

EasyExcel 文档 https://www.yuque.com/easyexcel/doc/easyexcel

课程上传的例子 https://www.bilibili.com/video/BV1dQ4y1A75e?from=search&seid=16041556233389040505

layui的upload文档说明 https://www.layui.com/doc/modules/upload.html

导出全部

使用到EasyExcel的写Excel,这一点也是最难的一点,主要是卡在文件在浏览器中下载。

如果直接使用EasyExcel中简单写的例子,只能将xlsx文件下载到后端的项目文件中,不能在浏览器中下载。

后端

	@GetMapping("exportAll")
public void exportAll(HttpServletResponse response) throws IOException {
List<UserDataExcel> listExcel = new ArrayList<>();
List<User> list = userService.list();
for(int i = 0;i<list.size();i++){
UserDataExcel dataExcel = new UserDataExcel();
BeanUtils.copyProperties(list.get(i),dataExcel);//小技巧
if(list.get(i).getType()!=null){//处理数据库中存放int 不是String
switch (list.get(i).getType()){
case 0:
dataExcel.setTypeStr("管理员");
break;
case 1:
dataExcel.setTypeStr("宿管员");
break;
case 2:
dataExcel.setTypeStr("学生");
break;
}
}
listExcel.add(dataExcel);
}
//文件名需要这样写,不能在setHeader直接写中文名,否则下载的文件名字为空,只有后缀
String fileName = new String("用户信息.xlsx".getBytes(), StandardCharsets.ISO_8859_1);
response.setContentType("application/msexcel");
response.setCharacterEncoding("utf8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName );
EasyExcel.write(response.getOutputStream(), UserDataExcel.class)
.sheet("sheet")
.doWrite(listExcel);
// return Result.ok().mesaage("下载成功"); 不要写
}

如果加了return Result.ok().mesaage("下载成功");后端会报错,但是还是可以正常下载。

org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.dj.dormitory.commonutils.Result] with preset Content-Type 'application/msexcel;charset=utf8'

前端

<button class="layui-btn  layui-btn-sm " lay-event="exportData" style="background: #27ae60"> 导出全部 </button>

刚开始的时候,自己想直接使用windows.open('/接口地址'),但是因为项目中用到token,所以就放弃了这个方法。使用了下面的方法

layer.confirm('确定导出所有用户信息吗?', {
btn: ['确定', '取消']
}, function(index){
//window.open("http://localhost:8888/dormitory/user/exportAll");
axios({
method: 'get',
url:'/user/exportAll',
responseType: 'blob', // 重要, 限制返回的数据结构为blob格式,方便前端做转换
}).then(data=>{
const link = document.createElement('a')
const blob = new Blob([data], { type: 'application/vnd.ms-excel' })
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.setAttribute('download','用户信息.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
layer.close(index);
}, function(index){
//按钮【按钮二】的回调
});

参考链接:

学到了 web中的代码具体应该怎么写

EasyExcel web中的写 https://www.yuque.com/easyexcel/doc/write#afb7324a

了解到window.open("/download");,可以在浏览器中实现成功下载了

EasyExcel实现下载Excel(解决无法从浏览器下载问题)https://blog.csdn.net/ruanbigshuai/article/details/108554896

了解到window.open("/download");最简单,但是不可以携带token

axios实现excel文件下载 https://blog.csdn.net/xuesheng1610748/article/details/83865679

成功帮助到自己的方法三,使用token并且在浏览器中实现成功下载了

Vue项目利用axios请求接口下载excel(附前后端代码) https://blog.csdn.net/asmallprogrammer/article/details/91440793

使用Layui、Axios、Springboot(Java) 实现EasyExcel的导入导出(浏览器下载)的更多相关文章

  1. 使用VUE+SpringBoot+EasyExcel 整合导入导出数据

    使用VUE+SpringBoot+EasyExcel 整合导入导出数据 创建一个普通的maven项目即可 项目目录结构 1 前端 存放在resources/static 下 index.html &l ...

  2. java实现excel的导入导出(poi详解)[转]

    java实现excel的导入导出(poi详解) 博客分类: java技术 excel导出poijava  经过两天的研究,现在对excel导出有点心得了.我们使用的excel导出的jar包是poi这个 ...

  3. java实现文件批量导入导出实例(兼容xls,xlsx)

    1.介绍 java实现文件的导入导出数据库,目前在大部分系统中是比较常见的功能了,今天写个小demo来理解其原理,没接触过的同学也可以看看参考下. 目前我所接触过的导入导出技术主要有POI和iRepo ...

  4. Java实现大批量数据导入导出(100W以上) -(二)导出

    使用POI或JXLS导出大数据量(百万级)Excel报表常常面临两个问题: 1. 服务器内存溢出: 2. 一次从数据库查询出这么大数据,查询缓慢. 当然也可以分页查询出数据,分别生成多个Excel打包 ...

  5. Java实现大批量数据导入导出(100W以上) -(一)导入

    最近业务方有一个需求,需要一次导入超过100万数据到系统数据库.可能大家首先会想,这么大的数据,干嘛通过程序去实现导入,为什么不直接通过SQL导入到数据库. 大数据量报表导出请参考:Java实现大批量 ...

  6. java 中Excel的导入导出

    部分转发原作者https://www.cnblogs.com/qdhxhz/p/8137282.html雨点的名字  的内容 java代码中的导入导出 首先在d盘创建一个xlsx文件,然后再进行一系列 ...

  7. java的excel表格的导出与下载

    今天做一个java对excel表格的导出和下载的时候,从网络上搜寻了下载的模板,代码如下: 控制层: @RequestMapping(value = "excelOut_identifier ...

  8. Java实现大批量数据导入导出(100W以上) -(三)超过25列Excel导出

    前面一篇文章介绍大数据量导出实现: Java实现大批量数据导入导出(100W以上) -(二)导出 这篇文章在Excel列较少时,按以上实际验证能很快实现生成.但如果列较多时用StringTemplat ...

  9. JAVA对Excel的导入导出

    今天需要对比2个excel表的内容找出相同:由于要学的还很多上手很慢所以在这做个分享希望对初学的有帮助: 先是pom的配置: <dependency> <groupId>org ...

随机推荐

  1. Shtml、html、xhtml、htm以及SSI的了解与认识(转载)

    Shtml.html.xhtml.htm以及SSI的了解与认识(转载) 一.htm.html.shtml网页区别(博客园) 文章链接:https://www.cnblogs.com/Renyi-Fan ...

  2. 从yield到yield from再到python协程

    yield 关键字 def fib(): a,b = 0,1 while 1: yield b a,b = b,a+b yield是在:PEP 255 -- Simple Generators 这个p ...

  3. 翻译:《实用的Python编程》06_03_Producers_consumers

    目录 | 上一节 (6.2 自定义迭代) | 下一节 (6.4 生成器表达式) 6.3 生产者,消费者和管道 生成器在设置各种生产者/消费者问题(producer/consumer problems) ...

  4. SpringBoot-02 运行原理初探

    SpringBoot-02 运行原理初探 本篇文章根据b站狂神编写 pom.xml 2.1.父依赖 其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件! <parent> < ...

  5. JAVA 写一个方法,判断一个整数是否为素数

    1 import java.util.Scanner; 2 3 public class Question3 { 4 public static void main(String[] args) { ...

  6. Android Studio 报错:你的主机中的软件中止了一个已建立的连接

    •解决方案 关闭电脑的移动热点 关闭后,build 就不会报错了. 等 build 好了后,重新打开移动热点,再次 build 一就不会报错.

  7. PAT (Basic Level) Practice (中文)1070 结绳 (25 分) 凌宸1642

    PAT (Basic Level) Practice (中文)1070 结绳 (25 分) 凌宸1642 题目描述 给定一段一段的绳子,你需要把它们串成一条绳.每次串连的时候,是把两段绳子对折,再如下 ...

  8. MySQL常用配置参数说明

    1.sync_binlog sync_binlog=0,当事务提交之后,MySQL不做fsync之类的磁盘同步指令刷新binlog_cache中的信息到磁盘,而让Filesystem自行决定什么时候来 ...

  9. 那些你可能不知道的 ZooKeeper 知识

    本文作者:HelloGitHub-老荀 Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源.有趣.入门级的 ZooKeeper 教程,面向有编程基础的新手. 项 ...

  10. Java(56-64)【IDEA】

    1.IDEA的使用 集成开发软件 eclipse IDEA 第一步:创建新的项目 第二步:空白的project 第三步:modules->java 写在src中 src->package- ...