本文使用的技术是Alibaba开源的EasyExcel技术,该技术是针对Apache POI技术的封装和优化,主要解决了POI技术的耗内存问题,并且提供了较好的API使用。不需要大量的代码就可以实现excel的操作功能。亲测可以导出100w条数据
demo源码如有需要接自行下载:https://download.csdn.net/download/weixin_39297312/15080971
com.alibaba easyexcel 1.1.2-beta4
excel工具类
/** * @program: easyexceldemo * @description: 异常 * @author: 羸鹄 * @create: 2021-02-05 09:16 **/ public class ExcelException extends RuntimeException { public ExcelException(String message) { super(message); } }
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
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 ListreadExcel(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 extends BaseRowModel> 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 extends BaseRowModel> 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; } }
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 extends BaseRowModel> 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(); } } }
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; } }
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 + '\'' + '}'; } }
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 { Listlist = 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("---------------"); } } }
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; } }
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) { Listlist = 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); } }