EasyExcel 自定义策略,实现动态列宽,非注解方式
1 背景:
excel 导出时,可能会遇到 导出列表 表头项 不固定,且每项的宽度不统一,例如:性别 可能只需要 10个宽度,但是地址 可能就需要 30个甚至50个宽度。
2 EasyExcel 官方提供的动态列宽解决方案
2.1 实体类中使用注解
以下代码为官方示例代码
@Getter
@Setter
@EqualsAndHashCode
@ContentRowHeight(10)
@HeadRowHeight(20)
@ColumnWidth(25)
public class WidthAndHeightData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;/*** 宽度为50*/@ColumnWidth(50)@ExcelProperty("数字标题")private Double doubleData;
}
因为 我们是动态表头,没有固定的实体类没法使用,不符合需求,PASS
2.2 官方提供的自动调整列宽的策略LongestMatchColumnWidthStyleStrategy
实体类
@Getter
@Setter
@EqualsAndHashCode
public class LongestMatchColumnWidthData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题很长日期标题很长日期标题很长很长")private Date date;@ExcelProperty("数字")private Double doubleData;
}
具体代码
/*** 自动列宽(不太精确)* * 这个目前不是很好用,比如有数字就会导致换行。而且长度也不是刚好和实际长度一致。 所以需要精确到刚好列宽的慎用。 当然也可以自己参照* {@link LongestMatchColumnWidthStyleStrategy}重新实现.*
* poi 自带{@link SXSSFSheet#autoSizeColumn(int)} 对中文支持也不太好。目前没找到很好的算法。 有的话可以推荐下。**
* 1. 创建excel对应的实体对象 参照{@link LongestMatchColumnWidthData}*
* 2. 注册策略{@link LongestMatchColumnWidthStyleStrategy}*
* 3. 直接写即可*/@Testpublic void longestMatchColumnWidthWrite() {String fileName =TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx";// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭EasyExcel.write(fileName, LongestMatchColumnWidthData.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong());}private List dataLong() {List list = new ArrayList();for (int i = 0; i < 10; i++) {LongestMatchColumnWidthData data = new LongestMatchColumnWidthData();data.setString("测试很长的字符串测试很长的字符串测试很长的字符串" + i);data.setDate(new Date());data.setDoubleData(1000000000000.0);list.add(data);}return list;}
方案二 和 方案一 有一样的问题,动态表头没有具体的实体类,且 此方案 生成的列宽不太精确,故也PASS ,但是 这个方案为我们提供了一种思路,我们是否可以通过自定义一个策略来实现动态表头的策略。
3 最终方案:自定义列宽策略
通过读取表头的配置,借助easyexcel 提供的 回调方法对 表头列宽进行设置。
3.1 定义 表头信息的实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TableHeaderVO implements Serializable {/*** 序列化ID*/private static final long serialVersionUID = 1L;/*** 字段对应数据*/private String prop;/*** 表头名称*/private String label;/*** 展示顺序*/private Integer index;/*** 展示宽度*/private Long width;/*** 是否自适应* true为自适应* false为非自适应* 默认为false*/private Boolean fixed = false;
}
表头信息,包括表头的列中文名 label、列属性 prop 、列宽 width 等属性,我们可以配置在数据库中,查询后使用TableHeaderVO 类进行接收查询结果。
3.2 自定义列宽策略
public class ColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {private static final int MAX_COLUMN_WIDTH = 255;private Map> sheetHeaderMap;public ColumnWidthStyleStrategy(Map> sheetHeaderMap) {this.sheetHeaderMap = sheetHeaderMap;}@Overrideprotected void setColumnWidth(WriteSheetHolder writeSheetHolder,List> cellDataList,Cell cell,Head head,Integer relativeRowIndex,Boolean isHead) {final int rowIndex = cell.getRowIndex();
// 只在第一行设置列宽即可 if (rowIndex != 0) {return;}final List list = sheetHeaderMap.get(writeSheetHolder.getSheetName());Integer columnWidth = dataLength(list, cell);if (columnWidth < 0) {return;}if (columnWidth > MAX_COLUMN_WIDTH) {columnWidth = MAX_COLUMN_WIDTH;}Integer maxColumnWidth = 1;if (columnWidth > maxColumnWidth) {writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);}}// 根据 cell 中写入的内容,查找该列配置的表头列宽private Integer dataLength(List list, Cell cell) {final String cellValue = cell.getStringCellValue();final Optional headerOptional =list.stream().filter(k -> cellValue.equals(k.getLabel())).findFirst();return headerOptional.map(tableHeaderVO -> tableHeaderVO.getWidth().intValue()).orElse(1);}
最终效果如下:

生效,完美解决
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
