EasyExcel 的 github 地址: https://github.com/alibaba/easyexceljava
首先是添加该项目的依赖,目前的版本是 1.0.2git
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>1.0.2</version> </dependency>
工具类,能够直接调用该工具类的方法完成 Excel 的读或者写github
/** * Created with IntelliJ IDEA * * @Author yuanhaoyue swithaoy@gmail.com * @Description 工具类 * @Date 2018-06-06 * @Time 14:07 */ public class ExcelUtil { /** * 读取 Excel(多个 sheet) * * @param excel 文件 * @param rowModel 实体类映射,继承 BaseRowModel 类 * @return Excel 数据 list */ public static List<Object> 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<Object> 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<Object> 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; } }
监听类,能够根据须要与本身的状况,自定义处理获取到的数据,我这里只是简单地把数据添加到一个 List 里面。api
public class ExcelListener extends AnalysisEventListener { //自定义用于暂时存储data。 //能够经过实例获取该值 private List<Object> datas = new ArrayList<>(); /** * 经过 AnalysisContext 对象还能够获取当前 sheet,当前行等数据 */ @Override public void invoke(Object object, AnalysisContext context) { //数据存储到list,供批量处理,或后续本身业务逻辑处理。 datas.add(object); //根据本身业务作处理 doSomething(object); } private void doSomething(Object object) { } @Override public void doAfterAllAnalysed(AnalysisContext context) { /* datas.clear(); 解析结束销毁不用的资源 */ } public List<Object> getDatas() { return datas; } public void setDatas(List<Object> datas) { this.datas = datas; } }
用于导出多个 sheet 的 Excel,经过屡次调用 write 方法写入多个 sheet并发
/** * Created with IntelliJ IDEA * * @Author yuanhaoyue swithaoy@gmail.com * @Description * @Date 2018-06-07 * @Time 16:47 */ 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(); } } }
捕获相关 Exceptionapp
/** * Created with IntelliJ IDEA * * @Author yuanhaoyue swithaoy@gmail.com * @Description Excel 解析 Exception * @Date 2018-06-06 * @Time 15:56 */ public class ExcelException extends RuntimeException { public ExcelException(String message) { super(message); } }
读取 Excel 时只须要调用 ExcelUtil.readExcel()
方法框架
@RequestMapping(value = "readExcel", method = RequestMethod.POST) public Object readExcel(MultipartFile excel) { return ExcelUtil.readExcel(excel, new ImportInfo()); }
其中 excel 是 MultipartFile 类型的文件对象,而 new ImportInfo() 是该 Excel 所映射的实体对象,须要继承 BaseRowModel 类,如:ide
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; } }
做为映射实体类,经过 @ExcelProperty 注解与 index 变量能够标注成员变量所映射的列,同时不可缺乏 setter 方法工具
只须要调用 ExcelUtil.writeExcelWithSheets()
方法:字体
@RequestMapping(value = "writeExcel", method = RequestMethod.GET) public void writeExcel(HttpServletResponse response) throws IOException { List<ExportInfo> list = getList(); String fileName = "一个 Excel 文件"; String sheetName = "第一个 sheet"; ExcelUtil.writeExcel(response, list, fileName, sheetName, new ExportInfo()); }
fileName,sheetName 分别是导出文件的文件名和 sheet 名,new ExportInfo() 为导出数据的映射实体对象,list 为导出数据。
对于映射实体类,能够根据须要经过 @ExcelProperty 注解自定义表头,固然一样须要继承 BaseRowModel 类,如:
public class ExportInfo extends BaseRowModel { @ExcelProperty(value = "姓名" ,index = 0) private String name; @ExcelProperty(value = "年龄",index = 1) private String age; @ExcelProperty(value = "邮箱",index = 2) private String email; @ExcelProperty(value = "地址",index = 3) private String address; }
value 为列名,index 为列的序号
若是须要复杂一点,能够实现以下图的效果:
对应的实体类写法以下:
public class MultiLineHeadExcelModel extends BaseRowModel { @ExcelProperty(value = {"表头1","表头1","表头31"},index = 0) private String p1; @ExcelProperty(value = {"表头1","表头1","表头32"},index = 1) private String p2; @ExcelProperty(value = {"表头3","表头3","表头3"},index = 2) private int p3; @ExcelProperty(value = {"表头4","表头4","表头4"},index = 3) private long p4; @ExcelProperty(value = {"表头5","表头51","表头52"},index = 4) private String p5; @ExcelProperty(value = {"表头6","表头61","表头611"},index = 5) private String p6; @ExcelProperty(value = {"表头6","表头61","表头612"},index = 6) private String p7; @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7) private String p8; @ExcelProperty(value = {"表头6","表头62","表头622"},index = 8) private String p9; }
调用 ExcelUtil.writeExcelWithSheets()
处理第一个 sheet,以后调用 write()
方法依次处理以后的 sheet,最后使用 finish()
方法结束
public void writeExcelWithSheets(HttpServletResponse response) throws IOException { List<ExportInfo> 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(); }
write 方法的参数为当前 sheet 的 list 数据,当前 sheet 名以及对应的映射类