EasyExcel的用法
一.Excel导入导出的应用场景
1.数据导入:减轻录入的工作量
2.数据导出:统计信息归档
3.数据传输:异构系统之间数据传输
二。EasyExcel简介
1.EasyExcel特点
Java领域解析,生成Excel比较有名的框架有Apache poi,jxl等,但他们都存在一个严重的问题就是非常的耗内存,如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc.
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单,节省内存著称,EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。
三、整合项目测试
1、添加pom依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
2、编写entity对象类
@Data
public class UserData {
@ExcelProperty(value = "用户编号",index = 0)
private int uid;
@ExcelProperty(value = "用户名称",index = 1)
private String username;
}
3、测试写操作
public class TestWrite {
public static void main(String[] args) {
//构建数据的集合
List<UserData> list = new ArrayList<>();
for (int i=0;i<10;i++) {
UserData data = new UserData();
data.setUid(i);
data.setUsername("lucc"+i);
list.add(data);
}
//设置excel文件的路径和文件的名称
String fileName = "D:\\excel\\02.xlsx";
//调用方法实现写的操作
EasyExcel.write(fileName,UserData.class).sheet("用户的信息")
.doWrite(list);
}
}
4、读取excel需要先写一个监听器继承AnalysisEventListener
public class ExcelListener extends AnalysisEventListener<UserData> {
//一行一行读取excle中的内容,从第二行开始读取
@Override
public void invoke(UserData userData, AnalysisContext analysisContext) {
System.out.println(userData);
}
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
System.out.println("表头信息"+headMap);
}
//读取之后执行
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
5、测试读操作
public class TestRead {
public static void main(String[] args) {
//读取文件的路径和名称
String fileName = "D:\\excel\\02.xlsx";
//调用方法实现读取操作
EasyExcel.read(fileName,UserData.class,new ExcelListener()).sheet().doRead();
}
}
四、项目中使用
model
@Data
@ApiModel(description = "数据字典")
@TableName("dict")
public class Dict {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private Date createTime;
@ApiModelProperty(value = "更新时间")
@TableField("update_time")
private Date updateTime;
@ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")
@TableLogic
@TableField("is_deleted")
private Integer isDeleted;
@ApiModelProperty(value = "其他参数")
@TableField(exist = false)
private Map<String,Object> param = new HashMap<>();
@ApiModelProperty(value = "上级id")
@TableField("parent_id")
private Long parentId;
@ApiModelProperty(value = "名称")
@TableField("name")
private String name;
@ApiModelProperty(value = "值")
@TableField("value")
private String value;
@ApiModelProperty(value = "编码")
@TableField("dict_code")
private String dictCode;
@ApiModelProperty(value = "是否包含子节点")
@TableField(exist = false)
private boolean hasChildren;
}
vo
@Data
public class DictEeVo {
@ExcelProperty(value = "id" ,index = 0)
private Long id;
@ExcelProperty(value = "上级id" ,index = 1)
private Long parentId;
@ExcelProperty(value = "名称" ,index = 2)
private String name;
@ExcelProperty(value = "值" ,index = 3)
private String value;
@ExcelProperty(value = "编码" ,index = 4)
private String dictCode;
}
controller层
//导出
@GetMapping("/exportData")
public void exportData(HttpServletResponse response) {
dictService.exportDicData(response);
}
//导入
@PostMapping("/importData")
public Result importData(MultipartFile file) {
dictService.importData(file);
return Result.ok();
}
service层
@Override
public void exportDicData(HttpServletResponse response) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和EASYEXCEL没有关系
String fileName = URLEncoder.encode("数据字典", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
//查询数据库
List<Dict> dictList = baseMapper.selectList(null);
ArrayList<DictEeVo> dictEeVoList = new ArrayList<>();
for (Dict dict:dictList) {
DictEeVo dictEeVo = new DictEeVo();
BeanUtils.copyProperties(dict,dictEeVo);
dictEeVoList.add(dictEeVo);
}
//调用方法进行写的操作
EasyExcel.write(response.getOutputStream(),DictEeVo.class).sheet("dict").doWrite(dictEeVoList);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void importData(MultipartFile file) {
try {
EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(dictMapper)).sheet().doRead();
} catch (IOException e) {
e.printStackTrace();
}
}
监听器继承AnalysisEventListener,这里需要注意的点,因为业务层的DictListener并没有交给Spring容器来管理,所以监听器代码无法注入DictListener,
这里通过构造方法的方式传过来,从而完成对数据库的操作。
public class DictListener extends AnalysisEventListener<DictEeVo> {
private DictMapper dictMapper;
public DictListener(DictMapper dictMapper) {
this.dictMapper = dictMapper;
}
//一行一行读取excle中的内容,从第二行开始读取
@Override
public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
Dict dict = new Dict();
BeanUtils.copyProperties(dictEeVo,dict);
dict.setIsDeleted(0);
dictMapper.insert(dict);
}
//读取之后执行
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}