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 名以及對應的映射類