一、說明
最近公司開發一個財務使用的系統,報表比較多。 以前用過POI,JXL,也遇到過OOM問題, 所以學習一下阿里的Excel工具:https://github.com/alibaba/easyexcel
開發中主要用到:
① 簡單數據導出,也就是查詢實體導出(這里一般會自定義導出某些字段)
②自定義單元格樣式,比如高亮顯示"小計","總計"行等
③合並單元格
那就先來試試簡單數據導出吧
二、pom引入
從官方文檔上,目前版本2.2.0-beta1,那我們隨便選一個2.X的版本,網上資料一般是1.1.1版本的,1.X和2.X版本個人感覺差別是有點大的~~
<!-- 阿里開源EXCEL -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<!-- <version>1.1.1</version>-->
<version>2.1.6</version>
</dependency>
三、准備工作
這里准備兩個實體,一個是官方文檔的實體 DemoData類(帶注解),一個是自定義的User類
@Data public class DemoData { @ExcelProperty("字符串標題") private String string; @ExcelProperty("日期標題") private Date date; @ExcelProperty("數字標題") private Double doubleData; /** * 忽略這個字段 */ @ExcelIgnore private String ignore; }
@Data public class User { private String uid; private String name; private Integer age; private Date birthday; }
准備模擬數據
/** * 模擬實體數據 * * @return */ private List<DemoData> getDemoDataList() { List<DemoData> list = new ArrayList<DemoData>(); for (int i = 0; i < 10; i++) { DemoData data = new DemoData(); data.setString("字符串" + i); //data.setDate(new Date()); //設置屬性一部分為空值 if (i % 2 == 0) { data.setDoubleData(null); } else { data.setDate(new Date()); } data.setDoubleData(0.56); list.add(data); } return list; } /** * 模擬實體數據 * * @return */ private List<User> getUserList() { List<User> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { User user = new User(); user.setUid("識別碼" + i); user.setAge(i * 10); //設置屬性一部分為空值 if (i % 2 == 0) { user.setBirthday(new Date()); } else { user.setBirthday(null); } user.setName("用戶名" + i); list.add(user); } return list; }
在盤符准備2個Excel文件用於導入數據,我用的是 I:\\temp\\writeDemo1.xlsx 和 I:\\temp\\writeDemo2.xlsx
設置表頭和內容的策略,這個是官方文檔復制過來的。
/** * 獲取策略,這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現 * * @return */ private HorizontalCellStyleStrategy getHorizontalCellStyleStrategy() { // 頭的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景設置為紅色 headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); WriteFont headWriteFont = new WriteFont(); headWriteFont.setFontHeightInPoints((short) 10); headWriteCellStyle.setWriteFont(headWriteFont); // 內容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); // 這里需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無法顯示背景顏色.頭默認了 FillPatternType所以可以不指定 //contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); // 背景綠色 //contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); //WriteFont contentWriteFont = new WriteFont(); // 字體大小 //contentWriteFont.setFontHeightInPoints((short)20); //contentWriteCellStyle.setWriteFont(contentWriteFont); // 這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現 HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); return horizontalCellStyleStrategy; }
四、設置列寬
1.X的版本是通過生成sheet,使用sheet設置寬度,2.X版本后大部分方法已經過期,不推薦使用了,而大部分都是使用EasyExcel類直接構造並實現大部分功能;
根據官方文檔的提示只需要注冊寫入處理器就可以了(WriteHandler),我這里直接復制一份過來修修改改~紅色代碼部分主要是關鍵部分
/** * 自定義攔截器 * * @author */ public class CustomSheetWriteHandler implements SheetWriteHandler { //列寬集合 private List<Integer> columnWidths; //構造 public CustomSheetWriteHandler(List<Integer> columnWidths) { this.columnWidths = columnWidths; } private static final Logger LOGGER = LoggerFactory.getLogger(CustomSheetWriteHandler.class); @Override public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { } @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { LOGGER.info("第{}個Sheet寫入成功。", writeSheetHolder.getSheetNo()); // 區間設置 第一列第一行和第二行的數據。由於第一行是頭,所以第一、二行的數據實際上是第二三行 /* CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 2, 0, 0); DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper(); DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"測試1", "測試2"}); DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList); writeSheetHolder.getSheet().addValidationData(dataValidation);*/ LOGGER.info("普通策略設置setColumnWidth開始~"); if(CollectionUtils.isNotEmpty(columnWidths)){ for (int i = 0; i < columnWidths.size(); i++) { writeSheetHolder.getSheet().setColumnWidth(i, columnWidths.get(i)); } } LOGGER.info("普通策略設置setColumnWidth結束~"); } }
五、根據注解導出數據到Excel文件中
/** * 寫入到固定文件中 * * @throws IOException */ @Test public void writeToExcelFile() { //寫入的文excel文件 String fileName = "I:\\temp\\writeDemo1.xlsx"; //獲取頭和內容的策略 HorizontalCellStyleStrategy horizontalCellStyleStrategy = getHorizontalCellStyleStrategy(); //列寬的策略,寬度是小單位 Integer columnWidthArr[] = {3000, 6000}; List<Integer> columnWidths = Arrays.asList(columnWidthArr); CustomSheetWriteHandler customSheetWriteHandler = new CustomSheetWriteHandler(columnWidths); // 根據用戶傳入字段 假設我們只要導出 string date String[] filds = {"string", "date"}; //獲取模擬的實體數據集合 List<DemoData> demoDataList = getDemoDataList(); //這里需要指定寫用哪個class去寫,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, DemoData.class) .registerWriteHandler(horizontalCellStyleStrategy) .registerWriteHandler(customSheetWriteHandler) //這個是導出需要展示的列 .includeColumnFiledNames(Arrays.asList(filds)) .sheet("模板") .doWrite(demoDataList); }
效果:
六、自定義導出列數據到Excel文件中
/** * 寫入到固定文件中,這里不使用注解的方式寫入列和對應的屬性 * * @throws IOException */ @Test public void writeToExcelFile2() { //寫入的文excel文件 String fileName = "I:\\temp\\writeDemo2.xlsx"; //獲取頭和內容的策略 HorizontalCellStyleStrategy horizontalCellStyleStrategy = getHorizontalCellStyleStrategy(); //列寬的策略,寬度是小單位 Integer columnWidthArr[] = {3000, 3000, 2000, 6000}; List<Integer> columnWidths = Arrays.asList(columnWidthArr); CustomSheetWriteHandler customSheetWriteHandler = new CustomSheetWriteHandler(columnWidths); // 根據用戶傳入字段 假設我們只要導出 string date String[] filds = {"uid", "name", "age", "birthday"}; String[] headers = {"唯一識別碼", "姓名", "年齡", "生日"}; List head = getHeadByFilds(headers); //獲取模擬的實體數據集合 List<User> userList = getUserList(); //這里指定頭的名字去寫入,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName) .head(head) .registerWriteHandler(horizontalCellStyleStrategy) .registerWriteHandler(customSheetWriteHandler) .includeColumnFiledNames(Arrays.asList(filds)) .sheet("模板") .doWrite(userList); }
效果:
六、總結
后面繼續實現合並單元格、自定義單元格、web導出和導入等功能~