java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > EasyExcel自定义Converter

Java中EasyExcel使用自定义Converter处理方法详解

作者:transitory_truth

EasyExcel自定义Converter是指在使用EasyExcel进行Excel读写操作时,可以自定义转换器来处理一些不支持的数据类型,这篇文章主要给大家介绍了关于Java中EasyExcel使用自定义Converter处理的相关资料,需要的朋友可以参考下

需求背景

类型处理报错

系统使用EasyExcel作为导入导出,有些类型操作会报转换异常:

com.alibaba.excel.exception.ExcelWriteDataConvertException: Can not find 'Converter' support class XXX.

这个问题的原因是因为找不到指定的converter去处理当前类型,默认的各种Converter去com.alibaba.excel.converters包下查看,或者直接查看Converter的各个实现类。作者主要是需要实现LocalDate的导出,其他类型同理。

枚举字段转换

还有一个场景是,如果这个字段的值本身是固定的枚举code,但是导出时要导出成文字。也可以使用。

其他说明

作者当前使用的easyExcel的版本为3.0.5。某些版本内置类名称不太一致,Api有些调整,不过都大同小异。

查看官方文档时发现其对自定义Converter的描述不太完整,特此记录

代码编写

重写converter

public class SpecClassConverter implements Converter<SpecClass> {}
// 以下为实现方法
Class<?> supportJavaTypeKey();
// 支持数据转换的java类型, 例如: return LocalDate.class/Integer.class/Boolean.class/customClass.class;
CellDataTypeEnum supportExcelTypeKey();
// 支持数据转换的单元格类型, 例如: return CellDataTypeEnum.STRING;
T convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty,GlobalConfiguration globalConfiguration);
// 将单元格内容转换成java对象;导入时使用 例如: return LocalDate.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));/return cellData.getStringValue().equals("是") ? 1 : 0; 注意自己处理空指针/空数据问题
T convertToJavaData(ReadConverterContext<?> context);
//  return convertToJavaData(context.getReadCellData(), context.getContentProperty(),context.getAnalysisContext().currentReadHolder().globalConfiguration());
// 估计是旧版本Api,默认实现调用上面方法,所以只重写上面方法就可以了 
WriteCellData<?> convertToExcelData(T value, ExcelContentProperty contentProperty,GlobalConfiguration globalConfiguration);
// 将java对象导出为指定单元格内容 例如: return new WriteCellData<>((LocalDate)value.format(DateUtil.formatter1));/return new WriteCellData<>((Integer)value == 1 ? "是" : "否"); 更多单元格样式设置请参照官方文档
WriteCellData<?> convertToExcelData(WriteConverterContext<T> context);
//  return convertToExcelData(context.getValue(), context.getContentProperty(),context.getWriteContext().currentWriteHolder().globalConfiguration());
// 估计是旧版本Api,默认实现调用上面方法,所以只重写上面方法就可以了 

使用converter

进阶使用

在数据转换时可以对单元格格式做操作,比如设置不同的单元格颜色、设置不同的字体、设置不同的字号

对于旧实体的处理 (例如: 数字脱敏)

实体类内字段指定使用Converter

// 代码很简单,重写converter的时候指定处理规则,然后将要脱敏的字段指定使用该Converter
@Override
    public WriteCellData<String> convertToExcelData(String value, ExcelContentProperty contentProperty,
                                               GlobalConfiguration globalConfiguration) throws IOException {
                String s = value.replaceAll("[0123456789]", "*");
        WriteCellData<String> res = new WriteCellData<>(s);
        return res;
    }

旧有实体类改造,实体类太多,原字段没有指定converter,固定了要处理的字段名或者指定了 @ExcelProperty 内的value

// 代码思路是在类上注册这个转换器,因为我们有个系统是提数系统,所有的导出最后统一由一个ExcelWriterBuilder处理,所以这个方式很省力
@Override
    public WriteCellData<String> convertToExcelData(String value, ExcelContentProperty contentProperty,
                                               GlobalConfiguration globalConfiguration) throws IOException {
        WriteCellData<String> res;
        Field field = contentProperty.getField();
        // 固定字段值 为了判断当前字段是否处理,获取当前字段的名称,进行判断
      	if(field.getName().equals("handler")){
            String s = value.replaceAll("[0123456789]", "*");
            res = new WriteCellData<>(s);
        }else{
            res = new WriteCellData<>(value);
        }
		// 字段值不固定,指定了 @ExcelProperty 注解中的value,固定导出列头,利用反射拿到注解
		ExcelProperty annotation = contentProperty.getField().getAnnotation(ExcelProperty.class);
        String resValue = value;
        if (annotation != null) {
            String[] value1 = annotation.value();
            String name = value1[value1.length-1];
            if(name.contains("handler")){
                resValue = value.replaceAll("[0123456789]", "*");
            }
        }
        WriteCellData<String> res = new WriteCellData<>(resValue);
		
        
        return res;
    }

旧有实体类改造,没使用 @ExcelProperty 注解,header是List<List<String>>格式,不确定字段名称,只确定导出header

思路是获取到设置的head列表,根据当前列的索引值获取当前header,判断是否处理,在converter中无法获取当前columnIndex,所以放到了CellWriteHandler中。

// 查看registerWriteHandler方法,发现这个WriteHandler 的调用更像是一个链路,所以不用担心覆盖,可以注册多个CustomWriteHandler 
   public T registerWriteHandler(WriteHandler writeHandler) {
        if (parameter().getCustomWriteHandlerList() == null) {
            parameter().setCustomWriteHandlerList(new ArrayList<WriteHandler>());
        }
        parameter().getCustomWriteHandlerList().add(writeHandler);
        return self();
    }


public class CustomWriterHandler implements CellWriteHandler {
// 重写afterCellDataConverted方法,在数据转换处理后对单元格做操作
    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
    
        if(!isHead){
            int columnIndex = cell.getColumnIndex();
            List<String> strings = writeSheetHolder.getHead().get(columnIndex);
            String s = strings.get(strings.size() - 1);
            if(s.equals("handler")){
                    String stringValue = cellData.getStringValue();
                    String res = stringValue.replaceAll("[0123456789]", "*");
                    cellData.setStringValue(res);
            }
            
            // 下面这种写法如果碰到自定义Head会空指针,而且这种对数据的处理可以的话尽量放到Converter更好
            
            // if(head.getFieldName().equals("handler")){
            //     String stringValue = cellData.getStringValue();
            //     String s = stringValue.replaceAll("[0123456789]", "*");
            //     cellData.setStringValue(s);
            // }
        }
    }
}

总结 

到此这篇关于Java中EasyExcel使用自定义Converter处理方法的文章就介绍到这了,更多相关EasyExcel自定义Converter内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文