摘要:是阿里巴巴對封裝的一個庫,號稱解決了的問題,并且在使用上也更方便一些然而我在使用的時候發現還是有很多坑,其中一個比較頭疼的是對單個單元格樣式的設置。
EasyExcel是阿里巴巴對POI封裝的一個庫,號稱解決了POI的OOM問題,并且在使用上也更方便一些Github:[](https://github.com/alibaba/ea...
然而我在使用的時候發現還是有很多坑,其中一個比較頭疼的是對單個單元格樣式的設置。EasyExcel提供了一個BaseRowModel作為每行數據的一個模型,并且其中有一個屬性cellStyleMap代表每列樣式的集合,本來我以為這個只要在自己定義模型的時候,也把CellStyle定義進去就行了,然而,還是我想多了……定義了CellStyle并沒有什么卵用,這是第一個蛋疼的地方
/** * Excel基礎模型 * @author jipengfei */ public class BaseRowModel { /** * 每列樣式 */ private MapcellStyleMap = new HashMap (); public void addStyle(Integer row, CellStyle cellStyle){ cellStyleMap.put(row,cellStyle); } public CellStyle getStyle(Integer row){ return cellStyleMap.get(row); } public Map getCellStyleMap() { return cellStyleMap; } public void setCellStyleMap(Map cellStyleMap) { this.cellStyleMap = cellStyleMap; } }
后來測試半天,才發現創建CellStyle時必須通過一個Workbook對象來創建,而這個Workbook不能隨便新建一個對象完事兒,得用你當前寫入的Workbook來創建對應的CellStyle樣式才能起作用。然而……事情并沒有那么簡單,經過我對源碼的反復查看,EasyExcel生成excel表的步驟是用一個ExcelWriter來寫入數據,并沒有提供獲取Workbook的方法,不知道什么原因讓阿里巴巴不提供這樣一個接口……這是第二個蛋疼的地方
既然沒有提供接口,那就只能用反射來硬剛了,下面就直接上代碼了
我這里是在開始寫數據之前就將每張表的CellStyle與每張表關聯起來,再在后面的handler中獲取到這個CellStyle進行設置
package edu.uddp.util; import com.alibaba.excel.EasyExcelFactory; import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.event.WriteHandler; import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.write.ExcelBuilderImpl; import com.sun.corba.se.spi.orbutil.threadpool.Work; import edu.uddp.enums.CellStyleEnum; import edu.uddp.model.SignExcelRow; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.streaming.SXSSFSheet; import java.io.*; import java.lang.reflect.Field; import java.util.*; /** * 生成Excel表 * * @author Juzi * @date 2018/12/23 12:37 * Blog https://juzibiji.top */ public class ExcelUtil { private static Map> cellStyles = new HashMap<>(); /** * 使用java對象模型創建excel,并使用handler * 生成Excel格式為xlsx * * @param path Excel生成路徑 * @param headLineMun 表頭占幾行 * @param data 傳入的鍵值對數據(key為sheet名,value為sheet數據) * @param handler 自定義的EasyExcel Handler,不使用傳入null即可 * @param columnWidthMap 每列寬度 * @throws IOException */ public static void createExcelWithModelAndHandler( String path, int headLineMun, Map > data, WriteHandler handler, Map columnWidthMap, List cellStyleEnums) throws IOException { File file = new File(path); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } OutputStream out = new FileOutputStream(path); // ExcelWriter用于導出Excel ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(null, out, ExcelTypeEnum.XLSX, true, handler); // 構造單元格樣式 Workbook workbook = getWorkbook(writer); cellStyles.put(workbook, createCellStyle(workbook, cellStyleEnums)); // sheet的序號,從1開始 int i = 1; // 遍歷傳入的sheet名和sheet數據來創建sheet for (Map.Entry > entry : data.entrySet()) { Sheet sheet = new Sheet(i, headLineMun, entry.getValue().get(0).getClass(), entry.getKey(), null); sheet.setColumnWidthMap(columnWidthMap); writer.write(entry.getValue(), sheet); i++; } // 必須要調用finish(),否則數據不會寫入文件 writer.finish(); out.close(); } /** * **獲取workbook** * 因為EasyExcel這個庫設計的原因 * 只能使用反射獲取workbook * * @param writer * @return */ private static Workbook getWorkbook(ExcelWriter writer) { Workbook workbook = null; try { Class> clazz1 = Class.forName("com.alibaba.excel.ExcelWriter"); Field[] fs = clazz1.getDeclaredFields(); for (Field field : fs) { // 要設置屬性可達,不然會拋出IllegalAccessException異常 field.setAccessible(true); if ("excelBuilder".equals(field.getName())) { ExcelBuilderImpl excelBuilder = (ExcelBuilderImpl) field.get(writer); Class> clazz2 = Class.forName("com.alibaba.excel.write.ExcelBuilderImpl"); Field[] fs2 = clazz2.getDeclaredFields(); for (Field field2 : fs2) { field2.setAccessible(true); if ("context".equals(field2.getName())) { WriteContext context = (WriteContext) field2.get(excelBuilder); workbook = context.getWorkbook(); } } } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return workbook; } public static Map createCellStyle(Workbook workbook, List cellStyleEnums) { Map map = new HashMap<>(); for (CellStyleEnum cellStyleEnum : cellStyleEnums) { if (cellStyleEnum.getNo() == 1) { CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setBorderBottom(BorderStyle.THIN); //下邊框 cellStyle.setBorderLeft(BorderStyle.THIN);//左邊框 cellStyle.setBorderTop(BorderStyle.THIN);//上邊框 cellStyle.setBorderRight(BorderStyle.THIN);//右邊框 cellStyle.setAlignment(HorizontalAlignment.CENTER); map.put(cellStyleEnum.getName(), cellStyle); } else if (cellStyleEnum.getNo() == 2) { CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setBorderBottom(BorderStyle.THIN); //下邊框 cellStyle.setBorderLeft(BorderStyle.THIN);//左邊框 cellStyle.setBorderTop(BorderStyle.THIN);//上邊框 cellStyle.setBorderRight(BorderStyle.THIN);//右邊框 cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); map.put(cellStyleEnum.getName(), cellStyle); } } return map; } public static Map > getCellStyles() { return cellStyles; } }
EasyExcel提供了一個WriteHandler,我們實現這個接口,就可以在每個單元格寫入之后或者每行寫入之前來進行攔截(這個handler設計的也很蛋疼),并注入我們自己的業務邏輯(設置單元格樣式)。
package edu.uddp.handler; import com.alibaba.excel.event.WriteHandler; import edu.uddp.util.ExcelUtil; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFSheet; import java.util.Map; /** * 第三方庫EasyExcel的Handler * 教師端生成簽到歷史表Excel時 * 將未簽到學生進行特殊標識 * * @author Juzi * @since 2018/12/22 22:07 * Blog https://juzibiji.top */ public class SignRecordExcelHandler implements WriteHandler { @Override public void sheet(int i, Sheet sheet) { } @Override public void row(int i, Row row) { } @Override public void cell(int i, Cell cell) { // 獲取當前workbook對應的CellStyle集合 MapcellStyleMap = ExcelUtil.getCellStyles().get(cell.getSheet().getWorkbook()); // 從第二行開始設置格式,第一行是表頭 if (cell.getRowIndex() > 0) { if (i == 7 && "未簽到".equals(cell.getStringCellValue())) { // 該生未簽到 for (int j = 0; j < 8; j++) { cell.getRow().getCell(j).setCellStyle(cellStyleMap.get("未簽到")); } } else if (i == 8 && "已簽到".equals(cell.getRow().getCell(7).getStringCellValue())) { // 該生已簽到 for (int j = 0; j < 9; j++) { cell.getRow().getCell(j).setCellStyle(cellStyleMap.get("已簽到")); } }else if(i == 8 && "未簽到".equals(cell.getRow().getCell(7).getStringCellValue())){ cell.setCellStyle(cellStyleMap.get("已簽到")); } } } }
上面有一些簡單的邏輯處理,就不一一介紹了。
若文章有任何問題,歡迎留言指出——作者博客:桔子筆記
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72841.html
摘要:背景小白今天閑著沒事,在公司摸魚,以為今天有事無聊的一天,突然上頭說小子,今天實現一下批量導入數據吧,當時我的內心是拒絕的,然后默默打開。介紹框架本身并不支持讀取,所有讀取需要借助一些框架。 1 背景 小白今天閑著沒事,在公司摸魚,以為今天有事無聊的一天,突然上頭說小子,今天實現一下批量導入Excel數據吧,當時我的內心是拒絕的,然后默默打開idea。 2 介紹 2.1 框架 java...
摘要:消費之后,多線程處理文件導出,生成文件后上傳到等文件服務器。前端直接查詢并且展現對應的任務執行列表,去等文件服務器下載文件即可。這客戶體驗不友好,而且網絡傳輸,系統占用多種問題。拓展閱讀導出最佳實踐框架 產品需求 產品經理需要導出一個頁面的所有的信息到 EXCEL 文件。 需求分析 對于 excel 導出,是一個很常見的需求。 最常見的解決方案就是使用 poi 直接同步導出一個 exc...
摘要:因為端和移動端布局差異較大,所以我將兩端布局分開講,本文章將針對端的布局進行講解,以下代碼只寫關鍵代碼。為了提高網頁性能,考慮到,表格元素盡量少用,有其他選擇的情況盡量用其他布局。 前言 此文章是 解剖CSS布局原理 的續集,之前那篇文章講的都是理論,本文章講具體的實例,根據自己對布局的理解與開發經驗分為以下幾類。 因為PC端和移動端布局差異較大,所以我將兩端布局分開講,本文章將針對P...
閱讀 2746·2021-11-16 11:45
閱讀 1654·2021-09-26 10:19
閱讀 2051·2021-09-13 10:28
閱讀 2803·2021-09-08 10:46
閱讀 1530·2021-09-07 10:13
閱讀 1525·2019-08-30 13:50
閱讀 1374·2019-08-30 11:17
閱讀 1455·2019-08-29 13:18