一、说明
最近公司开发一个财务使用的系统,报表比较多。 以前用过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导出和导入等功能~