EasyExcel大数据量导出

前言

            本文使用的技术是Alibaba开源的EasyExcel技术,该技术是针对Apache POI技术的封装和优化,主要解决了POI技术的耗内存问题,并且提供了较好的API使用。不需要大量的代码就可以实现excel的操作功能。亲测可以导出100w条数据

demo源码如有需要接自行下载:https://download.csdn.net/download/weixin_39297312/15080971

代码demo

EasyExcel大数据量导出_第1张图片

  1. pom依赖
    1. 
          com.alibaba
          easyexcel
          1.1.2-beta4
      
  2. excel工具类

    1. /**
       * @program: easyexceldemo
       * @description: 异常
       * @author: 羸鹄
       * @create: 2021-02-05 09:16
       **/
      public class ExcelException extends RuntimeException {
          public ExcelException(String message) {
              super(message);
          }
      }
      
    2. package com.example.easyexceldemo.utils;
      
      
      import com.alibaba.excel.context.AnalysisContext;
      import com.alibaba.excel.event.AnalysisEventListener;
      
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * @program: easyexceldemo
       * @description: 监听类
       * @author: 羸鹄
       * @create: 2021-02-05 09:16
       **/
      public class ExcelListener extends AnalysisEventListener {
      
      
          /**
           * 自定义用于暂时存储data。
           * 可以通过实例获取该值
           */
          private List datas = new ArrayList<>();
      
          public List getDatas() {
              return datas;
          }
      
          public void setDatas(List datas) {
              this.datas = datas;
          }
      
          /**
           * 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据
           */
          @Override
          public void invoke(Object object, AnalysisContext context) {
              //数据存储到list,供批量处理,或后续自己业务逻辑处理。
              datas.add(object);
              //根据业务自行 do something
              doSomething();
              /*
              如数据过大,可以进行定量分批处理
              if(datas.size()<=100){
                  datas.add(object);
              }else {
                  doSomething();
                  datas = new ArrayList();
              }
               */
      
          }
      
          /**
           * 根据业务自行实现该方法
           */
          private void doSomething() {
      
          }
      
          @Override
          public void doAfterAllAnalysed(AnalysisContext context) {
              /*
                  datas.clear();
                  解析结束销毁不用的资源
               */
          }
      }  
           
    3. package com.example.easyexceldemo.utils;
      
      import com.alibaba.excel.ExcelReader;
      import com.alibaba.excel.ExcelWriter;
      import com.alibaba.excel.metadata.BaseRowModel;
      import com.alibaba.excel.metadata.Sheet;
      import com.alibaba.excel.support.ExcelTypeEnum;
      import org.springframework.web.multipart.MultipartFile;
      
      import javax.servlet.http.HttpServletResponse;
      import java.io.*;
      import java.util.List;
      
      /**
       * @program: easyexceldemo
       * @description: 工具类
       * @author: 羸鹄
       * @create: 2021-02-05 09:16
       **/
      public class ExcelUtil {
      
          /**
           * 读取 Excel(多个 sheet)
           * @param excel    文件
           * @param rowModel 实体类映射,继承 BaseRowModel 类
           * @return Excel 数据 list
           */
          public static List readExcel(MultipartFile excel, BaseRowModel rowModel) {
              ExcelListener excelListener = new ExcelListener();
              ExcelReader reader = getReader(excel, excelListener);
              if (reader == null) {
                  return null;
              }
              for (Sheet sheet : reader.getSheets()) {
                  if (rowModel != null) {
                      sheet.setClazz(rowModel.getClass());
                  }
                  reader.read(sheet);
              }
              return excelListener.getDatas();
          }
      
          /**
           * 读取某个 sheet 的 Excel
           * @param excel    文件
           * @param rowModel 实体类映射,继承 BaseRowModel 类
           * @param sheetNo  sheet 的序号 从1开始
           * @return Excel 数据 list
           */
          public static List readExcel(MultipartFile excel, BaseRowModel rowModel, int sheetNo) {
              return readExcel(excel, rowModel, sheetNo, 1);
          }
      
          /**
           * 读取某个 sheet 的 Excel
           * @param excel       文件
           * @param rowModel    实体类映射,继承 BaseRowModel 类
           * @param sheetNo     sheet 的序号 从1开始
           * @param headLineNum 表头行数,默认为1
           * @return Excel 数据 list
           */
          public static List readExcel(MultipartFile excel, BaseRowModel rowModel, int sheetNo,
                                               int headLineNum) {
              ExcelListener excelListener = new ExcelListener();
              ExcelReader reader = getReader(excel, excelListener);
              if (reader == null) {
                  return null;
              }
              reader.read(new Sheet(sheetNo, headLineNum, rowModel.getClass()));
              return excelListener.getDatas();
          }
      
          /**
           * 导出 Excel :一个 sheet,带表头
           * @param response  HttpServletResponse
           * @param list      数据 list,每个元素为一个 BaseRowModel
           * @param fileName  导出的文件名
           * @param sheetName 导入文件的 sheet 名
           * @param object    映射实体类,Excel 模型
           */
          public static void writeExcel(HttpServletResponse response, List list,
                                        String fileName, String sheetName, BaseRowModel object) {
              ExcelWriter writer = new ExcelWriter(getOutputStream(fileName, response), ExcelTypeEnum.XLSX);
              Sheet sheet = new Sheet(1, 0, object.getClass());
              sheet.setSheetName(sheetName);
              writer.write(list, sheet);
              writer.finish();
          }
      
          /**
           * 导出 Excel :多个 sheet,带表头
           * @param response  HttpServletResponse
           * @param list      数据 list,每个元素为一个 BaseRowModel
           * @param fileName  导出的文件名
           * @param sheetName 导入文件的 sheet 名
           * @param object    映射实体类,Excel 模型
           */
          public static ExcelWriterFactroy writeExcelWithSheets(HttpServletResponse response, List list,
                                                                     String fileName, String sheetName, BaseRowModel object) {
              ExcelWriterFactroy writer = new ExcelWriterFactroy(getOutputStream(fileName, response), ExcelTypeEnum.XLSX);
              Sheet sheet = new Sheet(1, 0, object.getClass());
              sheet.setSheetName(sheetName);
              writer.write(list, sheet);
              return writer;
          }
      
          /**
           * 导出文件时为Writer生成OutputStream
           */
          private static OutputStream getOutputStream(String fileName, HttpServletResponse response) {
              //创建本地文件
              String filePath = fileName + ".xlsx";
              File dbfFile = new File(filePath);
              try {
                  if (!dbfFile.exists() || dbfFile.isDirectory()) {
                      dbfFile.createNewFile();
                  }
                  fileName = new String(filePath.getBytes(), "ISO-8859-1");
                  response.addHeader("Content-Disposition", "filename=" + fileName);
                  return response.getOutputStream();
              } catch (IOException e) {
                  throw new ExcelException("创建文件失败!");
              }
          }
      
          /**
           * 返回 ExcelReader
           * @param excel         需要解析的 Excel 文件
           * @param excelListener new ExcelListener()
           */
          private static ExcelReader getReader(MultipartFile excel,
                                               ExcelListener excelListener) {
              String filename = excel.getOriginalFilename();
              if (filename == null || (!filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".xlsx"))) {
                  throw new ExcelException("文件格式错误!");
              }
              InputStream inputStream;
              try {
                  inputStream = new BufferedInputStream(excel.getInputStream());
                  return new ExcelReader(inputStream, null, excelListener, false);
              } catch (IOException e) {
                  e.printStackTrace();
              }
              return null;
          }
      }
        
           
    4. package com.example.easyexceldemo.utils;
      
      import com.alibaba.excel.ExcelWriter;
      import com.alibaba.excel.metadata.BaseRowModel;
      import com.alibaba.excel.metadata.Sheet;
      import com.alibaba.excel.support.ExcelTypeEnum;
      
      import java.io.IOException;
      import java.io.OutputStream;
      import java.util.List;
      
      /**
       * @program: easyexceldemo
       * @description:
       * @author: 羸鹄
       * @create: 2021-02-05 09:16
       **/
      public class ExcelWriterFactroy extends ExcelWriter {
          private OutputStream outputStream;
          private int sheetNo = 1;
      
          public ExcelWriterFactroy(OutputStream outputStream, ExcelTypeEnum typeEnum) {
              super(outputStream, typeEnum);
              this.outputStream = outputStream;
          }
      
          public ExcelWriterFactroy write(List list, String sheetName,
                                          BaseRowModel object) {
              this.sheetNo++;
              try {
                  Sheet sheet = new Sheet(sheetNo, 0, object.getClass());
                  sheet.setSheetName(sheetName);
                  this.write(list, sheet);
              } catch (Exception ex) {
                  ex.printStackTrace();
                  try {
                      outputStream.flush();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
              return this;
          }
      
          @Override
          public void finish() {
              super.finish();
              try {
                  outputStream.flush();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
    5. excel实体类
      1. package com.example.easyexceldemo.model;
        
        import com.alibaba.excel.annotation.ExcelProperty;
        import com.alibaba.excel.metadata.BaseRowModel;
        
        /**
         * @program: easyexceldemo
         * @description: 导出 Excel 时使用的映射实体类
         * @author: 羸鹄
         * @create: 2021-02-05 09:16
         **/
        public class ExportInfo extends BaseRowModel {
            @ExcelProperty(value = "备件名称" ,index = 0)
            private String partName;
        
            @ExcelProperty(value = "原厂编码OEM",index = 1)
            private String firmNo;
        
            @ExcelProperty(value = "备件编码",index = 2)
            private String partNo;
        
            @ExcelProperty(value = "维修厂",index = 3)
            private String deptName;
        
            public String getPartName() {
                return partName;
            }
        
            public void setPartName(String partName) {
                this.partName = partName;
            }
        
            public String getFirmNo() {
                return firmNo;
            }
        
            public void setFirmNo(String firmNo) {
                this.firmNo = firmNo;
            }
        
            public String getPartNo() {
                return partNo;
            }
        
            public void setPartNo(String partNo) {
                this.partNo = partNo;
            }
        
            public String getDeptName() {
                return deptName;
            }
        
            public void setDeptName(String deptName) {
                this.deptName = deptName;
            }
        }
        
      2. package com.example.easyexceldemo.model;
        
        import com.alibaba.excel.annotation.ExcelProperty;
        import com.alibaba.excel.metadata.BaseRowModel;
        
        /**
         * @program: easyexceldemo
         * @description: 导入 Excel 时使用的映射实体类,Excel 模型
         * @author: 羸鹄
         * @create: 2021-02-05 09:16
         **/
        public class ImportInfo extends BaseRowModel {
            @ExcelProperty(index = 0)
            private String name;
        
            @ExcelProperty(index = 1)
            private String age;
        
            @ExcelProperty(index = 2)
            private String email;
        
            /*
                作为 excel 的模型映射,需要 setter 方法
             */
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public String getAge() {
                return age;
            }
        
            public void setAge(String age) {
                this.age = age;
            }
        
            public String getEmail() {
                return email;
            }
        
            public void setEmail(String email) {
                this.email = email;
            }
        
            @Override
            public String toString() {
                return "Info{" +
                        "name='" + name + '\'' +
                        ", age='" + age + '\'' +
                        ", email='" + email + '\'' +
                        '}';
            }
        }
        
      3. package com.example.easyexceldemo.model;
        
        import java.util.ArrayList;
        import java.util.List;
        import java.util.concurrent.atomic.AtomicInteger;
        
        /**
         * @program: easyexceldemo
         * @description:
         * @author: 羸鹄
         * @create: 2021-02-05 10:57
         **/
        public class Test implements Runnable {
        
            List list = new ArrayList<>();
        
            private AtomicInteger count = new AtomicInteger(0);
        
            public List getList() {
                return list;
            }
        
            public void setList(List list) {
                this.list = list;
            }
        
            @Override
            public void run() {
                for (int i = 1000000; i > 0; i--) {
                    int incrementAndGet = count.incrementAndGet();
                    ExportInfo exportInfo = new ExportInfo();
                    exportInfo.setDeptName("维修厂" + incrementAndGet);
                    exportInfo.setFirmNo("" + incrementAndGet);
                    exportInfo.setPartName("" + incrementAndGet);
                    exportInfo.setPartNo("" + incrementAndGet);
                    list.add(exportInfo);
                }
                if (list.size() == 10) {
                    System.err.println("---------------");
                }
            }
        }
        
      4. package com.example.easyexceldemo.utils;
        
        
        import java.util.concurrent.*;
        
        /**
         * @program: easyexceldemo
         * @description:
         * @author: 羸鹄
         * @create: 2021-02-05 10:28
         **/
        public class ThreadPool {
        
            private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 8, 1000L, TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(1000), new ThreadPoolExecutor.DiscardOldestPolicy());
        
        
            public static Future submit(Runnable runnable){
                Future future = threadPoolExecutor.submit(runnable);
                return future;
            }
        }
        
    6. controller
      1. package com.example.easyexceldemo.controlller;
        
        import com.example.easyexceldemo.model.ExportInfo;
        import com.example.easyexceldemo.model.ImportInfo;
        import com.example.easyexceldemo.model.Test;
        import com.example.easyexceldemo.utils.ExcelUtil;
        import com.example.easyexceldemo.utils.ThreadPool;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RequestMethod;
        import org.springframework.web.bind.annotation.RequestParam;
        import org.springframework.web.bind.annotation.RestController;
        import org.springframework.web.multipart.MultipartFile;
        
        import javax.servlet.http.HttpServletResponse;
        import java.io.IOException;
        import java.util.List;
        import java.util.concurrent.Future;
        
        /**
         * @program: easyexceldemo
         * @description: controller
         * @author: 羸鹄
         * @create: 2021-02-05 09:27
         **/
        @RestController
        @RequestMapping(value = "/excel")
        public class ExcelController {
        
            /**
             * 导出 Excel(一个 sheet)
             */
            @RequestMapping(value = "/exportExcel", method = RequestMethod.GET)
            public void exportExcel(HttpServletResponse response) {
                List list = getList();
                String fileName = "一个 Excel 文件";
                String sheetName = "第一个sheet";
                ExcelUtil.writeExcel(response, list, fileName, sheetName, new ExportInfo());
            }
        
        
            /**
             * 导出 多个Excel(多个 sheet)
             */
            @RequestMapping(value = "/exportMultiExcel", method = RequestMethod.GET)
            public void exportMultiExcel(HttpServletResponse response) {
                List list = getList();
                String fileName = "一个 Excel 文件";
                String sheetName1 = "第一个 sheet";
                String sheetName2 = "第二个 sheet";
                String sheetName3 = "第三个 sheet";
                ExcelUtil.writeExcelWithSheets(response, list, fileName, sheetName1, new ExportInfo())
                        .write(list, sheetName2, new ExportInfo())
                        .write(list, sheetName3, new ExportInfo()).finish();
            }
        
        
            private List getList() {
                Test test = new Test();
                Future future = ThreadPool.submit(test);
                try {
                    future.get();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                List list = test.getList();
                return list;
            }
        
        
            /**
             * 读取 Excel(允许多个 sheet)
             */
            @RequestMapping(value = "/readExcelWithSheets", method = RequestMethod.POST)
            public Object readExcelWithSheets(MultipartFile excel) {
                return ExcelUtil.readExcel(excel, new ImportInfo());
            }
        
            /**
             * 读取 Excel(指定某个 sheet)
             */
            @RequestMapping(value = "/readExcel", method = RequestMethod.POST)
            public Object readExcel(MultipartFile excel, int sheetNo,
                                    @RequestParam(defaultValue = "1") int headLineNum) {
                return ExcelUtil.readExcel(excel, new ImportInfo(), sheetNo, headLineNum);
            }
        
        }
    7. 结果展示
      1. EasyExcel大数据量导出_第2张图片
      2. EasyExcel大数据量导出_第3张图片
    8.  

      你可能感兴趣的:(java技术,poi,easyexcel)