easyexcel文件上传
前言:功能开发中,难免碰到数据上传下载功能,excel上传常见用于报表上传,绩效上传,考勤上传...
使用步骤:
1,编写业务层:
1,添加easyexcel依赖
c
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.2.0</version>
</dependency>
2,导入模板excel下载
通常有个模版下载功能,在模板里面添加表头,以及数据格式...
3,在导入Excel模版中添加导入数据
4,导入
controller
c
@PostMapping("/importxxxRoster")
@ApiOperation("导入xxx信息")
public void importxxxRoster(MultipartFile file, HttpServletResponse response) {
dutyRosterService.importDutyRoster(file, response);
}
service
c
/**
* 导入xxx信息
*
* @param file
* 文件
* @param response
* 响应
*/
void importxxxRoster(MultipartFile file, HttpServletResponse response);
serviceImpl
c
@Override
public void importxxxRoster(MultipartFile file, HttpServletResponse response) {
try {
InputStream is = file.getInputStream();
// 监听器不能放在容器里面,要通过构造器的方式,放入监听器使用
xxxxRosterDataListener listener = new xxxxRosterDataListener(this.baseMapper);
// xxxRosterData 接收导入Excel 实体类
EasyExcel.read(is, xxxRosterData.class, listener).doReadAll();
// 获取错误信息集合
List<xxxRosterErrorData> errorDataList = listener.getErrorDataList();
if (!CollectionUtils.isEmpty(errorDataList)) {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("xxx导入错误详情", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// 导出错误Excel数据
EasyExcel.write(response.getOutputStream(), xxxRosterErrorData.class).sheet("错误详情").doWrite(errorDataList);
}
} catch (IOException e) {
log.error("导入xxexcel异常:{}", e);
// 编写异常信息
}
}
接收导入Excel 数据实体
xxxRosterData
c
package com.xx.xx.xx.entity.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* @author psd xxx导入excel 接收数据实体
*
*/
@Data
public class xxxRosterData {
/**
* 值班时间str
*/
@ExcelProperty(value = "日期",order = 0)
private String dutyTimeStr;
/**
* 人员名称
*/
@ExcelProperty(value = "人员名称",order = 1)
private String person;
}
2,编写监听器
c
package com.xxx.xx.xx.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.xx.xx.common.result.ResultCodeEnum;
import com.xx.xx.common.utils.DateUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author psd 创建xx信息导入监听器
*/
@Data
public class xxxRosterDataListener extends AnalysisEventListener<xxxRosterData> {
XXXRosterMapper xxxRosterMapper;
/**
* 记录批量导入数据
*/
private List<xxxRosterEntity> batchInsertDutyList = new ArrayList<>();
/**
* 记录需要更新的数据
*/
private List<xxxRosterEntity> batchUpdateDutyList = new ArrayList<>();
/**
* 记录错误的数据
*/
private List<xxxRosterErrorData> errorDataList = new ArrayList<>();
/**
* 记录没有问题的数据集合
*/
private List<xxxxRosterEntity> normalData = new ArrayList<>();
// 创建构造器 引入用到的service mapper...
public xxRosterDataListener(xxxRosterMapper dutyRosterMapper) {
this.xxRosterMapper = xxxRosterMapper;
}
/**
* 每一条数据都会解析
*
* @param data
* 每行数据
* @param analysisContext
*/
@Override
public void invoke(xxxRosterData data, AnalysisContext analysisContext) {
// 1、添加常见的行数校验
// 2、参数校验
if (validateData(data)) {
// 说明没有问题
// 3、编写要导入的数据对象信息放入
normalData.add(xxx);
}
}
/**
* 常见的数据校验
*
* @param data
* 每一行的数据集
* @return 是否异常 true 数据基本判断没有问题,false 说明有异常
*/
private boolean validateData(xxxxRosterData data) {
StringBuffer errorMsg = new StringBuffer();
// 清空字符串
errorMsg.setLength(ConstantUtils.ZERO);
// 添加数据校验
if (StringUtils.isBlank(errorMsg)) {
// 说明没有问题
return true;
} else {
// 记录错误信息
errorDataList.add();
return false;
}
}
/**
* 所有数据执行完才会调用
*
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 1、获取没有问题的数据
// 2、判断哪些是新增的 哪些是需要修改的
// 3、批量入库
。。。
}
}
常见遇到的问题:
问题一:
下载模板导入Excel时候明明写了数据,但是错误数据还是为空的问题,或者导入不成功?
原因是:
1,Excel的表头字段名字要和接收的数据Vo对象里面的字段名称一致
比如:
Excel模板中的表头为:
数据接收对象的字段名称为
导致接收不到
2,有可能是排序的问题,比如上图日期在第一位,但是数据xxxData实体类接收对象
order = 不是0,也会导致没有接收到数据
问题二:
在监听器添加注解比如@Component ... 或者其他注解,使用@Autowired 、或者@Resources注解引入xxxService 、xxxMapper ,引入的service和mapper无法使用
这个是因为监听器不支持这种引入,可以通过构造器方式将数据传递过去,监听器不是放在spring容器中【这点是自己的理解,可能有误】
问题三:
错误信息如何导出?
我们可以在监听器添加@Data注解通过getxxx()方式获取错误数据,可以做成导出Excel功能。
c
@Data
public class xxxRosterDataListener extends AnalysisEventListener<xxxRosterData> {
/**
* 记录错误的数据
*/
private List<xxxRosterErrorData> errorDataList = new ArrayList<>();
......
}
c
@Override
public void importxxxRoster(MultipartFile file, HttpServletResponse response) {
try {
.....
// 获取错误信息集合
List<DutyRosterErrorData> errorDataList = listener.getErrorDataList();
if (!CollectionUtils.isEmpty(errorDataList)) {
// 导出Excel
}
} catch (IOException e) {
// 抛异常 ...
}
}
喜欢我的文章的话,点个阅读或者点个点赞,是我编写博客的动力,持续更新中 ing...