最近公司项目需要实现国际化,参考easy excel官方文档对导出的文件对国际化支持不是很友好。
先来看官方文档实现的方案
/**
* 可变标题处理(包括标题国际化等)
* <p>
* 简单的说用List<List<String>>的标题 但是还支持注解
* <p>
* 1. 创建excel对应的实体对象 参照{@link ConverterData}
* <p>
* 2. 直接写即可
*/
@Test
public void variableTitleWrite() {
// 写法1
String fileName = TestFileUtil.getPath() + "variableTitleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, ConverterData.class).head(variableTitleHead()).sheet("模板").doWrite(data());
}
private List<List<String>> variableTitleHead() {
List<List<String>> list = ListUtils.newArrayList();
List<String> head0 = ListUtils.newArrayList();
head0.add("string" + System.currentTimeMillis());
List<String> head1 = ListUtils.newArrayList();
head1.add("number" + System.currentTimeMillis());
List<String> head2 = ListUtils.newArrayList();
head2.add("date" + System.currentTimeMillis());
list.add(head0);
list.add(head1);
list.add(head2);
return list;
} private List<List<String>> variableTitleHead() {
List<List<String>> list = new ArrayList<>();
List<String> head0 = new ArrayList<>();
head0.add("string" + System.currentTimeMillis());
List<String> head1 = new ArrayList<>();
head1.add("number" + System.currentTimeMillis());
List<String> head2 = new ArrayList<>();
head2.add("date" + System.currentTimeMillis());
list.add(head0);
list.add(head1);
list.add(head2);
return list;
}
@Getter
@Setter
@EqualsAndHashCode
public class ConverterData {
/**
* 我想所有的 字符串起前面加上"自定义:"三个字
*/
@ExcelProperty(value = "字符串标题", converter = CustomStringStringConverter.class)
private String string;
/**
* 我想写到excel 用年月日的格式
*/
@DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
@ExcelProperty("日期标题")
private Date date;
/**
* 我想写到excel 用百分比表示
*/
@NumberFormat("#.##%")
@ExcelProperty(value = "数字标题")
private Double doubleData;
}
关键代码是head(variableTitleHead()),相当于由variableTitleHead直接返回经过国际化处理后的标题。
这种实现方式个人觉得不是很优雅,原因有两点
- 原pojo类中
ExcelProperty注解失去意义 - 第二点,也是最重要的一点,就是当需要根据前端参数导出指定字段且按照指顺序排序的时,
variableTitleHead方法中需要返回需要自己实现以上逻辑,以保证生成的表头和数据字段一致且顺序一致。显然,这段逻辑与国际化无关,不应该写在这里,对于有代码强迫症的怎么能忍呢😂。
查看easy excel源码后,找到了一个算是投机取巧的办法,主要是改动代码相对减少了不少。关键代码如下
//需要导出的字段,从前端获取
Collection<String> includeFields=null;
//导出的数据
Collection<DataPOjO> list= null;
try (ExcelWriter excelWriter = EasyExcel.write(outputMessage.getBody(), excelData.getType()).includeColumnFieldNames(includeFields).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet("sheet名称")
.orderByIncludeColumn(true)
.build();
//ClassUtils为easy excel核心包中的类
//一定要在write方法之前执行下面2行代码
FieldCache fieldCache = ClassUtils.declaredFields(DataPOjO.class, excelWriter.writeContext().currentWriteHolder());
//处理国际化
processHead(fieldCache);
excelWriter.write(list, writeSheet);
}catch (Exception e){
log.error("",e);
}
//数据
@Data
class DataPOjO{
@ExcelProperty(value = "${i18n.key}")
private String name;
}
Pattern pattern= Pattern.compile("\$\{(.*)\}");
private void processHead(FieldCache fieldCache) {
Map<Integer, FieldWrapper> headMap = fieldCache.getSortedFieldMap();
for (Map.Entry<Integer, FieldWrapper> integerHeadEntry : headMap.entrySet()) {
FieldWrapper value = integerHeadEntry.getValue();
String[] heads = value.getHeads();
if(heads!=null&&heads.length >= 1){
String headStr = heads[0];
Matcher matcher = pattern.matcher(headStr);
if (matcher.find()) {
String i18nKey = matcher.group(1);
value.setHeads(new String[]{I18nMsgUtil.getMessage(i18nKey)});
}
}
}
}
通过processHead方法把原来通过ExcelProperty获取的字段名替换成i18n资源文件中的配置的名称