EasyExcel代码层面设置写出的Excel样式、以及拦截器策略的使用、自动列宽设置、EasyExcel默认设置详解
一、概述
虽然EasyExcel
已经提供了一系列注解方式去设置样式。
但是如果没有实体类,或者想要更精确的去设置导出文件的Excel
样式的时候就需要在代码层面去控制样式了。
二、使用已有拦截器自定义样式
主要步骤:
- 创建
Excel
对应的实体对象 - 创建一个
style
策略 并注册 - 写出
Excel
第一步是否需要创建Excel实体对象,得根据实际需求而定,如果导出字段不固定则使用无模型的方式即可
不使用实体类时可以直接传入List<List>类型的数据来作为表头和数据内容。
2.1 定义一个Excel实体类
@Getter
@Setter
@EqualsAndHashCode
public class DemoData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;/*** 忽略这个字段*/@ExcelIgnoreprivate String ignore;
}
2.2 设置表头样式
// 创建一个写出的单元格样式对象
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色
headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());// 创建写出Excel的字体对象
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short)20); // 设置字体大小为20
headWriteFont.setItalic(BooleanEnum.TRUE.getBooleanValue());// 设置字体斜体
headWriteCellStyle.setWriteFont(headWriteFont); // 把字体对象设置到单元格样式对象中
2.3 设置内容样式
// 创建一个写出的单元格样式对象
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND
// 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 设置内容背景色为绿色
contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());// 边框设置
contentWriteCellStyle.setBorderTop(BorderStyle.THIN); // 设置单元格上边框为细线
contentWriteCellStyle.setBorderBottom(BorderStyle.THICK); // 设置单元格下边框为粗线
contentWriteCellStyle.setBorderLeft(BorderStyle.MEDIUM); // 设置单元格左边框为中线
contentWriteCellStyle.setBorderRight(BorderStyle.MEDIUM_DASHED); // 设置单元格右边框为中虚线// 创建写出Excel的字体对象
WriteFont contentWriteFont = new WriteFont();
contentWriteFont.setFontHeightInPoints((short)20); //设置字体大小
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); //设置文字居中
contentWriteCellStyle.setWriteFont(contentWriteFont); // 把字体对象设置到单元格样式对象中
2.4 使用EasyExcel默认的拦截器策略自定义样式
常见的策略有两种:
HorizontalCellStyleStrategy
:每一行的样式都一样 或者隔行一样源码中它主要有两个构造函数:
// 构造函数一:接收一个WriteCellStyle对象和一个List<WriteCellStyle>集合 // 第一个参数是表头部分单元格的样式 // 第二个参数是内容部分的单元格样式 public HorizontalCellStyleStrategy(WriteCellStyle headWriteCellStyle,List<WriteCellStyle> contentWriteCellStyleList) {this.headWriteCellStyle = headWriteCellStyle;this.contentWriteCellStyleList = contentWriteCellStyleList; }// 构造函数二:接收两个WriteCellStyle对象 // 第一个参数是表头部分的单元格的样式 // 第二个参数是内容部分的单元格样式 public HorizontalCellStyleStrategy(WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) {this.headWriteCellStyle = headWriteCellStyle;if (contentWriteCellStyle != null) {this.contentWriteCellStyleList = ListUtils.newArrayList(new WriteCellStyle[]{contentWriteCellStyle});}}
WriteCellStyle
其实只是一个单元格的对象。把它交由
HorizontalCellStyleStrategy
之后,就可以被渲染成一行的对象。然后每行都按这个策略执行。接收
List<WriteCellStyle>
参数时,会循环渲染集合中的样式对象。AbstractVerticalCellStyleStrategy
:每一列的样式都一样 需要自己回调每一页它是一个抽象类,需要自己定义类去继承它,然后重写里面对应的方法。
这部分文档中的描述几乎没有,全靠自己摸索,可能官方更推荐第一种方式
2.5 使用默认的拦截器HorizontalCellStyleStrategy自定义样式
// 完整代码
@Test
public void handlerStyleWrite() {// 创建一个写出的单元格样式对象WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND// 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 设置内容背景色为绿色contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());// 边框设置contentWriteCellStyle.setBorderTop(BorderStyle.THIN); // 设置单元格上边框为细线contentWriteCellStyle.setBorderBottom(BorderStyle.THICK); // 设置单元格下边框为粗线contentWriteCellStyle.setBorderLeft(BorderStyle.MEDIUM); // 设置单元格左边框为中线contentWriteCellStyle.setBorderRight(BorderStyle.MEDIUM_DASHED);//设置单元格右边框为中虚线// 创建写出Excel的字体对象WriteFont contentWriteFont = new WriteFont();contentWriteFont.setFontHeightInPoints((short)20); //设置字体大小contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);//设置文字居中contentWriteCellStyle.setWriteFont(contentWriteFont); // 把字体对象设置到单元格样式对象中// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy horizontalCellStyleStrategy =new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("horizontalCellStyleStrategy拦截器设置样式").doWrite(data());}
2.5 使用默认的拦截器AbstractVerticalCellStyleStrategy自定义样式
1)创建一个类实现AbstractVerticalCellStyleStrategy
public class CustomVerticalCellStyleStrategy extends AbstractVerticalCellStyleStrategy {// 重写定义表头样式的方法@Overrideprotected WriteCellStyle headCellStyle(Head head) {WriteCellStyle writeCellStyle = new WriteCellStyle();writeCellStyle.setFillBackgroundColor(IndexedColors.RED.getIndex());WriteFont writeFont = new WriteFont();writeFont.setColor(IndexedColors.RED.getIndex());writeFont.setBold(false);writeFont.setFontHeightInPoints(Short.valueOf((short)15));writeCellStyle.setWriteFont(writeFont);return writeCellStyle;}// 重写定义内容部分样式的方法@Overrideprotected WriteCellStyle contentCellStyle(Head head) {WriteCellStyle writeCellStyle = new WriteCellStyle();writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);writeCellStyle.setFillBackgroundColor(IndexedColors.GREEN.getIndex());writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);return writeCellStyle;}
}
这个方式在背景色设置方面存在问题,不知道是不是bug,这种方式还是慎用吧
2)具体使用
@Test
public void handlerStyleWrite() {// 创建拦截器对象CustomVerticalCellStyleStrategy customVerticalCellStyleStrategy = new CustomVerticalCellStyleStrategy();// 写出ExcelEasyExcel.write(fileName, DemoData.class).registerWriteHandler(customVerticalCellStyleStrategy).sheet("horizontalCellStyleStrategy拦截器设置样式").doWrite(data());}
三、自定义拦截器设置Excel样式
3.1 为什么不使用AbstractCellWriteHandler
老版本中自定义拦截器主要是继承 Easyexcel
的抽象类AbstractCellWriteHandler
控制器。
重写beforeCellCreate
前置处理方法和afterCellDispose
后置处理方法完成对应的方法达到控制单个单元格
样式的效果。但是AbstractCellWriteHandler这个抽象类在3.x版本已经被弃用,所以现在不推荐使用它。
3.2 实现CellWriteHandler接口
前面的两种方式,都只能在代码层面批量设置样式,而不能设置导出Excel
中的一部分单元格样式。
实现这个接口后可以重写afterCellDispose
方法来对单个单元格的样式进行设置。
每个单元格处理完毕之后都会调用它。
虽然文档中说不太推荐,可能是这里代码多了会影响性能,但是这是目前设置单个单元格最好的方式了。
3.1 基础使用
1)定义类实现CellWriteHandler接口,并重写afterCellDispose方法
public class CustomCellWriteStrategy implements CellWriteHandler {// 在单元格处理之后执行@Overridepublic void afterCellDispose(CellWriteHandlerContext context) {// 当前事件会在 数据设置到poi的cell里面才会回调// 判断不是头的情况 如果是fill 的情况 这里会==null 所以用not trueif (BooleanUtils.isNotTrue(context.getHead())) {// 获取第一个单元格对象// 只要不是头 一定会有数据 当然fill(填充)的情况 可能要context.getCellDataList() // 这个需要看模板,因为一个单元格会有多个 WriteCellDataWriteCellData<?> cellData = context.getFirstCellData();// cellData 可以获取样式/数据,也可以直接设置样式/数据,设置后会立即生效// 这里也需要用cellData去获取样式// 很重要的一个原因是 WriteCellStyle 和 dataFormatData绑定的 // 简单的说 比如你加了 DateTimeFormat,已经将writeCellStyle里面的dataFormatData改了 // 如果你自己new了一个WriteCellStyle,可能注解的样式就失效了// 然后getOrCreateStyle 用于返回一个样式,如果为空,则创建一个后返回// (总之记住用这个方法获取样式即可)WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();writeCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND// 要不然背景色不会生效writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 获取当前单元格的数据,必要的时候可以根据数据来设置单元格的颜色// 比如当前列为状态列,数据为1是正常,背景色为绿色,反正不正常,背景色设置为红// 这种需求的实现将变得可能Object data = cellData.getStringValue();System.out.println("data: " + data);// 这样样式就设置好了 后面有个FillStyleCellWriteHandler 默认会将 WriteCellStyle 设置 到 cell里面去 所以可以不用管了}}
}
2)写出Excel时注册处理策略
@Test
public void handlerStyleWrite() {// 创建处理器策略对象CustomCellWriteStrategy customCellWriteStrategy = new CustomCellWriteStrategy();// 写出ExcelEasyExcel.write(fileName, DemoData.class).registerWriteHandler(customCellWriteStrategy).sheet("自定义单个单元格样式演示").doWrite(data());}
四、设置列宽
有实体类的时候,可以使用注解去设置列宽,但是如果是那种无模型的,又该怎么去设置列宽呢。
官方提供的LongestMatchColumnWidthStyleStrategy
,
4.1 AbstractColumnWidthStyleStrategy
1)基础写法
定义一个类,去继承AbstractColumnWidthStyleStrategy
这个抽象类,并且重写里面的setColumnWidth
方法
public class ExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {@Overrideprotected void setColumnWidth(WriteSheetHolder writeSheetHolder,List<WriteCellData<?>> cellDataList,Cell cell,Head head,Integer relativeRowIndex,Boolean isHead) {// 使用sheet对象 简单设置 index所对应的列的列宽Sheet sheet = writeSheetHolder.getSheet();sheet.setColumnWidth(cell.getColumnIndex(), 5000);}
}
每处理一个单元格都会调用一次setColumnWidth
方法,这个方法有两种重载,重写哪一个都行。
2)自适应列宽写法
public class ExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {// 单元格的最大宽度private static final int MAX_COLUMN_WIDTH = 50; // 缓存(第一个Map的键是sheet的index, 第二个Map的键是列的index, 值是数据长度)private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8); // 重写设置列宽的方法@Overrideprotected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);// 当时表头或者单元格数据列表有数据时才进行处理if (needSetWidth) {Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap == null) {maxColumnWidthMap = new HashMap(16);CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}// 获取数据长度Integer columnWidth = this.getLength(cellDataList, cell, isHead);if (columnWidth >= 0) {if (columnWidth > MAX_COLUMN_WIDTH) {columnWidth = MAX_COLUMN_WIDTH;}// 确保一个列的列宽以表头为主,如果表头已经设置了列宽,单元格将会跟随表头的列宽Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());if (maxColumnWidth == null || columnWidth > maxColumnWidth) {maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);// 如果使用EasyExcel默认表头,那么使用columnWidth * 512// 如果不使用EasyExcel默认表头,那么使用columnWidth * 256// 如果是自己定义的字体大小,可以再去测试这个参数常量writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 512);}}}}/*** 获取当前单元格的数据长度* @param cellDataList* @param cell* @param isHead* @return*/private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {WriteCellData cellData = cellDataList.get(0);CellDataTypeEnum type = cellData.getType();if (type == null) {return -1;} else {switch(type) {case STRING:return cellData.getStringValue().getBytes().length;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}}
可以根据自己的需求自行改造
4.2 写出Excel时注册处理策略
@Test
public void handlerStyleWrite() {// 创建处理器策略对象ExcelWidthStyleStrategy excelWidthStyleStrategy = new ExcelWidthStyleStrategy();// 写出ExcelEasyExcel.write(fileName, DemoData.class).registerWriteHandler(excelWidthStyleStrategy).sheet("单个单元格列宽设置").doWrite(data());
}
五、EasyExcel其它默认设置
5.1 表头自动合并
EasyExcel.write(response.getOutputStream(), DemoData.class).automaticMergeHead(false) // 自动合并表头.sheet("模板").doWrite(demoData);
若automaticMergeHead
设置为true
,那么对于相邻表格中存在相同内容单元格,easyexcel
会自动将其合并。
它的默认值也是true
。
如果不想使用表头自动合并,就设置为false
即可。
5.2 取消导出Excel的默认风格
EasyExcel.write(response.getOutputStream(), DemoData.class).useDefaultStyle(false) // 取消导出Excel的默认风格.sheet("模板").doWrite(demoData);
easyexcel
的默认风格是最明显的体现,对于表头会显示灰色背景,并且字体会加粗和放大。
如果不想使用这个默认风格,把useDefaultStyle
设置为false
即可。
5.3 是否使用1904日期窗口
EasyExcel.write(response.getOutputStream(), DemoData.class).use1904windowing(true) // 设置使用1904的时间格式.sheet("模板").doWrite(demoData);
EasyExcel
中时间是存储1900
年起的一个双精度浮点数。一般也是使用1900
的时间格式就可以了。
如果有业务想把开始日期改为1904
,就可以设置use1904windowing
为true
即可。
EasyExcel代码层面设置写出的Excel样式、以及拦截器策略的使用、自动列宽设置、EasyExcel默认设置详解相关推荐
- Java 通过EasyExcel导出的Excel文档的字体,背景色,自动列宽等符合要求
这次开任务使用的是EasyExcel导出Excel文档,但是在任务过程中,生成的文档的格式要求并不符合产品和测试的期望值,如图: 想着自己地位低下,也无能力反驳.只好硬着头皮查阅资料来达到他们的想要的 ...
- 深度学习研究生如何快速提升代码能力,写出高效的代码?
深度学习代码与前端代码区别 深度学习的代码能力与开发后台或者前端的工程代码能力不是一个概念. 写前端代码:脑海中是整个工程的架构,写代码则是把这些架构用 code 具体化. 写深度学习代码:脑海中浮现 ...
- 网页通过CSS写出生日倒计时(利用:日期倒计时、元素自动旋转、边框视觉按钮效果)[直接复制代码即可实现、含注释]
图片效果 ↓(代码为粉图,生日歌自动播放) 视频效果 ↓(音乐为自动播放) 网页通过CSS写出生日倒计时(利用:日期倒计时.元素自动旋转.边框视觉按钮效果) 代码 ↓(可直接复制使用,音乐引用网易云音 ...
- easyPoi单sheet与多sheet导出excel简单实用(重点:自动列宽的设置)
导入依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base< ...
- EasyExcel设置自动列宽
EasyExcel 可以通过设置自动列宽来调整表格中列的宽度.具体方法如下: 使用autoSizeColumn()方法:您可以通过调用autoSizeColumn()方法来设置自动列宽.该方法需要您指 ...
- POI单元格合并(合并后边框空白修复)、自动列宽、水平居中、垂直居中、设置背景颜色、设置字体等常见问题
POI单元格合并.自动列宽.水平居中.垂直居中.设置背景颜色.设置字体等常用方法 POI设置单元格样式 POI设置文字 POI设置边框样式 POI设置文字水平居中.垂直居中 POI设置背景颜色 POI ...
- pandas 导出 Excel 文件的时候自动列宽,自动加上边框
尝试过 xlrd.xlwt.openpyxl.xlwings.pandas 来处理 Excel,如果说除了读写 Excel,还要做数据分析,还是 pandas 最好用,大多数情况下,你根本不需要把数据 ...
- POI 设置单元格格式,单元格合并,自动列宽等
POI 设置单元格格式,单元格合并,自动列宽等 设置单元格样式 设置单元格背景 设置单元格合并 解决合并单元格遗留空白边框问题 设置单元格列宽自适应 设置单元格样式 第一种:日期格式 cell.set ...
- 错误代码,1302 行高列宽超出页面大小设置,解决方法
错误代码,1302 行高列宽超出页面大小设置,解决方法 使用报表报错: java.lang.RuntimeException: 错误代码:1302 行高列宽超出页面大小设置行 原因: 数据库表里面存在 ...
最新文章
- android datagrid demo
- HEU 4048 Picking Balls
- xftp permission is not allowed
- 第25节 典型应用集成技术
- (三十)java多线程一
- how debug option is handled - handle_debug
- r语言中1c0怎么表示什么,r语言表示或者用什么符号?
- 思维导图网页版、临时使用推荐工具——画图本
- Python知识点之Python面向对象
- Linux学习笔记(单用户模式,救援模式,克隆主机,两个linux互相连接)
- iOS 给测试人员测试手机APP的四种方法:真机运行(略),打ipa包,(testFlighe)邮件,蒲公英(二)testflight
- JetBrains系列产品学生认证申请免费使用教程
- (专升本)Excel(分页符的删除)
- 动手学深度学习(六、卷积神经网络)
- LeCo-121. 买卖股票的最佳时机
- 店盈通:拼多多直通车推广怎么操作?技巧有哪些?
- sql中替换字段的部分字符
- python中wheel什么意思_某个wheel(.whl)包的依赖关系是什么?
- windows 操作系统安全运维所考虑的安全基线内容
- 单线程与多线程使用场景