摘要:是阿里巴巴对封装的一个库,号称解决了的问题,并且在使用上也更方便一些然而我在使用的时候发现还是有很多坑,其中一个比较头疼的是对单个单元格样式的设置。
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("已签到")); } } } }
上面有一些简单的逻辑处理,就不一一介绍了。
若文章有任何问题,欢迎留言指出——作者博客:桔子笔记
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/72841.html
摘要:背景小白今天闲着没事,在公司摸鱼,以为今天有事无聊的一天,突然上头说小子,今天实现一下批量导入数据吧,当时我的内心是拒绝的,然后默默打开。介绍框架本身并不支持读取,所有读取需要借助一些框架。 1 背景 小白今天闲着没事,在公司摸鱼,以为今天有事无聊的一天,突然上头说小子,今天实现一下批量导入Excel数据吧,当时我的内心是拒绝的,然后默默打开idea。 2 介绍 2.1 框架 java...
摘要:消费之后,多线程处理文件导出,生成文件后上传到等文件服务器。前端直接查询并且展现对应的任务执行列表,去等文件服务器下载文件即可。这客户体验不友好,而且网络传输,系统占用多种问题。拓展阅读导出最佳实践框架 产品需求 产品经理需要导出一个页面的所有的信息到 EXCEL 文件。 需求分析 对于 excel 导出,是一个很常见的需求。 最常见的解决方案就是使用 poi 直接同步导出一个 exc...
摘要:因为端和移动端布局差异较大,所以我将两端布局分开讲,本文章将针对端的布局进行讲解,以下代码只写关键代码。为了提高网页性能,考虑到,表格元素尽量少用,有其他选择的情况尽量用其他布局。 前言 此文章是 解剖CSS布局原理 的续集,之前那篇文章讲的都是理论,本文章讲具体的实例,根据自己对布局的理解与开发经验分为以下几类。 因为PC端和移动端布局差异较大,所以我将两端布局分开讲,本文章将针对P...
阅读 2749·2021-11-16 11:45
阅读 1656·2021-09-26 10:19
阅读 2053·2021-09-13 10:28
阅读 2804·2021-09-08 10:46
阅读 1533·2021-09-07 10:13
阅读 1528·2019-08-30 13:50
阅读 1377·2019-08-30 11:17
阅读 1456·2019-08-29 13:18