EasyExcel是阿里巴巴对POI封装的一个库,号称解决了POI的OOM问题,并且在使用上也更方便一些Github:[](https://github.com/alibaba/ea…然而我在使用的时候发现还是有很多坑,其中一个比较头疼的是对单个单元格样式的设置。EasyExcel提供了一个BaseRowModel作为每行数据的一个模型,并且其中有一个属性cellStyleMap代表每列样式的集合,本来我以为这个只要在自己定义模型的时候,也把CellStyle定义进去就行了,然而,还是我想多了……定义了CellStyle并没有什么卵用,这是第一个蛋疼的地方/** * Excel基础模型 * @author jipengfei /public class BaseRowModel { /* * 每列样式 / private Map<Integer,CellStyle> cellStyleMap = new HashMap<Integer,CellStyle>(); public void addStyle(Integer row, CellStyle cellStyle){ cellStyleMap.put(row,cellStyle); } public CellStyle getStyle(Integer row){ return cellStyleMap.get(row); } public Map<Integer, CellStyle> getCellStyleMap() { return cellStyleMap; } public void setCellStyleMap(Map<Integer, CellStyle> 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<Workbook, Map<String, CellStyle>> 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<String, List<? extends BaseRowModel>> data, WriteHandler handler, Map<Integer, Integer> columnWidthMap, List<CellStyleEnum> 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<String, List<? extends BaseRowModel>> 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<CellStyleEnum> cellStyleEnums) { Map<String, CellStyle> 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<Workbook, Map<String, CellStyle>> 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集合 Map<String, CellStyle> cellStyleMap = 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(“已签到”)); } } }}上面有一些简单的逻辑处理,就不一一介绍了。若文章有任何问题,欢迎留言指出——作者博客:桔子笔记