Springboot 集成 EasyExcel

2022-07-11 12:37:31

1、引入Maven以来

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.1</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.17</version></dependency>

注意:POI的版本必须为3.17

2、编写模板类

import com.alibaba.excel.annotation.ExcelProperty;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;/**
 * @author zyq
 * @Description ExcelProperty为表头名称
 * @createTime 2021年01月22日 19:52:00
 */@Data@Builder@AllArgsConstructor@NoArgsConstructorpublicclassExcelDataVO{@ExcelProperty(value="编号", index=0)private Integer id;@ExcelProperty(value="姓名", index=1)private String name;}

3、EasyExcel工具类

import com.alibaba.excel.EasyExcel;import com.alibaba.excel.ExcelReader;import com.alibaba.excel.event.AnalysisEventListener;import com.alibaba.excel.read.metadata.ReadSheet;import com.alibaba.excel.support.ExcelTypeEnum;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.URLEncoder;import java.util.List;/**
 * @author zyq
 * @Description
 * @createTime 2021年01月22日 20:04:00
 */publicclassExcelUtils{/**
     * 导出Excel
     * @param response
     * @param list 数据
     * @param fileName 文件名称
     * @param sheetName 表名
     * @param clazz 指定导出模板类的类型
     */publicstaticvoidwriteExcel(HttpServletResponse response, List<?> list,
                                  String fileName, String sheetName, Class<?> clazz){
        EasyExcel.write(getOutputStream(fileName, response), clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).doWrite(list);}/**
     * 读取Excel中的数据
     * @param file
     * @param clazz
     * @param listener
     */publicstaticvoidreadExcel(MultipartFile file, Class<?> clazz, AnalysisEventListener<?> listener){
        ExcelReader excelReader= null;try{
            excelReader= EasyExcel.read(getInputStream(file), clazz, listener).build();
            ReadSheet readSheet= EasyExcel.readSheet(0).build();
            excelReader.read(readSheet);}finally{if(excelReader!= null){// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
                excelReader.finish();}}}/**
     * 导出文件时为Writer生成OutputStream
     * @param fileName
     * @param response
     * @return
     */privatestatic OutputStreamgetOutputStream(String fileName, HttpServletResponse response){try{
            fileName= URLEncoder.encode(fileName,"UTF-8");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf8");
            response.setHeader("Content-Disposition","attachment; filename="+ fileName+".xlsx");
            response.setHeader("Pragma","public");
            response.setHeader("Cache-Control","no-store");
            response.addHeader("Cache-Control","max-age=0");return response.getOutputStream();}catch(IOException e){thrownewApiException("导出excel表格失败!");}}/**
     * 导入文件时为Reader生成InputStream
     * @param file
     * @return
     */privatestatic InputStreamgetInputStream(MultipartFile file){try{return file.getInputStream();}catch(IOException e){thrownewApiException("导入excel表格数据失败!");}}}

5、导入Excel时需要监听器

import com.alibaba.excel.context.AnalysisContext;import com.alibaba.excel.event.AnalysisEventListener;import com.guli.service_edu.entity.EduTeacher;import com.guli.service_edu.mapper.EduTeacherMapper;import com.guli.service_edu.vo.ExcelDataVO;import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;import java.util.List;/**
 * @author zyq
 * @Description
 * ExcelDataListener 不能被spring管理,
 * 要每次读取excel都要new,然后里面用到spring可以构造方法传进
 * 每次创建Listener的时候需要把spring管理的类传进来
 * @createTime 2021年01月23日 14:23:00
 */@Slf4jpublicclassExcelDataListenerextendsAnalysisEventListener<ExcelDataVO>{/**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */privatestaticfinalint BATCH_COUNT=5;
    List<ExcelDataVO> list=newArrayList<>();/**
     * 每次创建Listener的时候需要把spring管理的类传进来
     */privatefinal EduTeacherMapper teacherMapper;publicExcelDataListener(EduTeacherMapper eduTeacherMapper){this.teacherMapper= eduTeacherMapper;}/**
     * 每一条数据解析都会来调用
     * @param data
     * @param context
     */@Overridepublicvoidinvoke(ExcelDataVO data, AnalysisContext context){
        log.info("【解析Excel数据】");
        list.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif(list.size()>= BATCH_COUNT){saveData();// 存储完成清理 list
            list.clear();}}/**
     * 所有数据解析完成了 都会来调用
     * @param context
     */@OverridepublicvoiddoAfterAllAnalysed(AnalysisContext context){// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();
        log.info("所有数据解析完成!");}/**
     * 加上存储数据库, 这里批量插入需要写一个服务层进行批量插入,
     * 避免在循环体中调用持久层的insert方法
     */privatevoidsaveData(){
        log.info("{}条数据,开始存储数据库!", list.size());for(ExcelDataVO vo: list){
            EduTeacher eduTeacher=newEduTeacher();
            eduTeacher.setAvatar(vo.getId()+ vo.getName());
            eduTeacher.setName(vo.getName());
            eduTeacher.setLevel(vo.getId());
            eduTeacher.setSort(vo.getId());
            eduTeacher.setIntro(vo.getName());
            teacherMapper.insert(eduTeacher);}
        log.info("存储数据库成功!");}}

4、控制层调用

@GetMapping("/excel")publicvoidexcel(HttpServletResponse response){
    List<ExcelDataVO> list=newArrayList<>();for(int i=1; i<10; i++){
        list.add(ExcelDataVO.builder().id(i).name("🐖👁掏"+ i).build());}try{
        ExcelUtils.writeExcel(response, list,"fileName","sheetName", ExcelDataVO.class);}catch(Exception e){thrownewApiException("EXCEL DOWNLOAD ERROR!");}}@ApiOperation("导入数据")@PostMapping("/excel")publicvoidaddExcel(MultipartFile file){try{
        ExcelUtils.readExcel(file, ExcelDataVO.class,newExcelDataListener(eduTeacherMapper));}catch(Exception e){thrownewApiException("EXCEL UPLOAD ERROR!");}}

注意:不需要对response.getOutputStream()进行flush和close,见参考文档

HttpServletResponse输入输出流是否需要flush close

EasyExcel官方文档地址EasyExcel

  • 作者:it00zyq
  • 原文链接:https://blog.csdn.net/weixin_43364551/article/details/113034894
    更新时间:2022-07-11 12:37:31