EasyExcel 自定义转换器、自定义导出字典映射替换、满足条件内容增加样式,完整代码+详细注释说明

虽然最之前是在其他地方看到的,但最终因缘巧合下找到了原文,还是尊重一下原作者。
参考引用了这位佬的博客,确实方便使用。
https://blog.csdn.net/qq_45914616/article/details/137200688?spm=1001.2014.3001.5502

如果想通过枚举类来做替换,而不是直接写替换内容的,请看另一篇:EasyExcel 自定义转换器、自定义导出枚举类替换,完整代码+详细注释说明

这是一个基于Easyexcel通过注解的方式,
在巨人的肩膀上,对相关方法进行了一定的调整和说明注释,方便使用与定制调整为自己所需要的内容格式。
能做到的事情有:

  1. 通过注解实现自定义字典值映射,满足数字、英文等符合格式的导出字典映射,导入也支持。
  2. 支持字典值映射的单选或多选模式
  3. 支持对满足某些条件的内容,在输出时添加一些样式,比如字体颜色。

以下正文:

1.定义了一个枚举类

/**
 * @Description: 符号枚举类
 * @author: CloverAn
 * @email: 
 * @created: 2023/02/27 21:01
 */
public class SymbolConstant {

    private SymbolConstant() {
    }

    public static final String SPE1 = ",";
 
    /**
     * 竖线
     */
    public static final String SPE9 = "\\|";

}

多余出来的已经做了删除,这两个使用了所以保留,各位可以自行替换修改。

2.添加自定义注解

import com.data.utils.constant.SymbolConstant;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Description: 枚举数值的自定义注解
 * @author: CloverAn
 * @email:
 * @created: 2024/06/25 15:57
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumFiledConvert {


    /**
     * 枚举映射map  key-value,key-value,key-value,key-value
     * <p>
     * key|value,key|value
     * <p>
     * 注意,这里的key和value都是英文字符串,所以实际上他可以是数字,也可以是英文,也可以是否个字符串
     * 例如:0|满勤,0-1|特殊,Y|是,n|error
     *
     * @return
     */
    String enumMap() default "未匹配到映射字典";

    /**
     * 枚举类导入、导出在excel中的分隔符号
     *
     * @return
     */
    String spiteChar() default SymbolConstant.SPE1;

    /**
     * 枚举类导入导出字典分隔符
     */
    String dictChar() default SymbolConstant.SPE9;

    /**
     * 单选 or 多选
     * <p>
     * 即多个枚举映射,都会比对输出,例如
     *
     * @return
     * @EnumFiledConvert(enumMap = "1-篮球,2-足球,3-乒乓球,4-羽毛球",single = false)
     * <p>
     * 字段值是"1,2,3,4"
     * 则最终输出的是"篮球,足球,乒乓球,羽毛球"
     * <p>
     * 字典值是"1,2"
     * 则最终输出的是"篮球,足球"
     */
    boolean single() default true;

    /**
     * 条件样式,对满足条件的字符串,设置红色字体
     */
    String fontColorMap() default "";
}

1.这里将原作者的直接使用符号,以及符合使用的 逗号和横杠 调整了以下,因为个人有这一块的需求,最终使用的是 逗号和竖线。
2.修改了默认值,添加了部分注释,更通俗易懂。
3.在作者原有的基础上,增加了字体颜色的注解属性,用于接收指定的判断条件和颜色要求

3.重写EasyExcel转换器接口,对excel读和写方法都进行自定义


import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.data.keepriskexport.utils.constant.SymbolConstant;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 导入导出针对枚举类型的转换器
 *
 * @author CloverAn
 */
public class EasyExcelConvert implements Converter<Object> {
    /**
     * 枚举列表
     */
    private Map<String, String> enumMap = new HashMap<>();
    /**
     * 条件列表
     */
    private Map<String, String> fontColorMap = new HashMap<>();


    /**
     * excel转化后的类型
     *
     * @return
     */
    @Override
    public Class<?> supportJavaTypeKey() {
        return Object.class;
    }

    /**
     * excel中的数据类型,统一设置字符串
     *
     * @return
     */
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 导入转换
     *
     * @param cellData            当前单元格对象
     * @param contentProperty     当前单元格属性
     * @param globalConfiguration
     * @return
     * @throws Exception
     */
    @Override
    public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        String cellMsg = cellData.getStringValue();
        Field field = contentProperty.getField();
        EnumFiledConvert enumFiledConvert = field.getAnnotation(EnumFiledConvert.class);
        if (enumFiledConvert == null) {
            return null;
        }
        String enumStr = enumFiledConvert.enumMap();
        // 解析枚举映射关系
        getEnumMap(enumStr, true);
        // 是否为单选
        boolean single = enumFiledConvert.single();
        // 如果是单选,默认Java属性为integer
        if (single) {
            String res = enumMap.get(cellMsg);
            return StringUtils.hasText(res) ? Integer.valueOf(res) : null;
        } else {
            // 多选分隔符
            String spiteChar = enumFiledConvert.spiteChar();
            // 多选枚举,默认Java属性为字符串,格式为 key1,key2,key3
            List<String> strStr = Arrays.asList(cellMsg.split(spiteChar)).stream().map(s -> String.valueOf(enumMap.get(s))).collect(Collectors.toList());
            String str = String.join(spiteChar, strStr);
            return str;
        }
    }

    /**
     * 导出转化
     *
     * @param value               当前值
     * @param contentProperty     当前单元格属性
     * @param globalConfiguration
     * @return
     * @throws Exception
     */
    @Override
    public WriteCellData<?> convertToExcelData(Object value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        Field field = contentProperty.getField();
        EnumFiledConvert enumFiledConvert = field.getAnnotation(EnumFiledConvert.class);
        if (enumFiledConvert == null) {
            return new WriteCellData();
        }
        // 解析枚举字符串
        String enumStr = enumFiledConvert.enumMap();
        getEnumMap(enumStr, false);
        // 是否为单选
        boolean single = enumFiledConvert.single();

        //条件样式
        String conditions = enumFiledConvert.fontColorMap();
        //解析条件样式
        getConditionsMap(conditions);


        // 如果是单选,默认Java属性为integer
        if (single) {
            //输出内容原始值
            String valueOf = String.valueOf(value);

            //输出内容转换,字典值
            String orDefault = enumMap.getOrDefault(valueOf, "");
            //创建输出内容
            WriteCellData writeCellData = new WriteCellData(orDefault);
            setWriteCellStyle(writeCellData, orDefault);

            return writeCellData;
        } else {
            // 多选分隔符
            String spiteChar = enumFiledConvert.spiteChar();
            // 多选枚举,默认Java属性为字符串,格式为 key1,key2,key3
            List<String> strStr = Arrays.asList(String.valueOf(value).split(spiteChar)).stream().map(s -> String.valueOf(enumMap.get(s))).collect(Collectors.toList());
            String str = String.join(spiteChar, strStr);
            WriteCellData writeCellData = new WriteCellData(str);

            return writeCellData;
        }
    }

    /**
     * 根据注解配置的枚举映射字符串进行解析到map中
     *
     * @param mapStr
     * @param readOrWrite 读excel 、 写excel
     */
    private void getEnumMap(String mapStr, boolean readOrWrite) {
        String[] enumS = mapStr.split(SymbolConstant.SPE1);
        for (String anEnum : enumS) {
            String[] data = anEnum.split(SymbolConstant.SPE9);
            if (readOrWrite) {
                // 读excel excel中的数据都是value,转换成key
                enumMap.put(data[1], data[0]);
            } else {
                // 写excel  Java中的数据都是key,转换成value
                enumMap.put(data[0], data[1]);
            }
        }
    }

    /**
     * 根据注解配置的枚举映射字符串进行解析到map中
     * 只有写出的时候生效
     */
    private void getConditionsMap(String conditions) {
        if (conditions != null && !conditions.isEmpty()) {
            String[] conditionsMaps = conditions.split(SymbolConstant.SPE1);
            for (String condition : conditionsMaps) {
                String[] data = condition.split(SymbolConstant.SPE9);
                // 写excel  Java中的数据都是key,转换成value
                fontColorMap.put(data[0], data[1]);
            }
        }
    }


    /**
     *
     * 取到什么颜色,填充什么颜色,没有则不填充。
     *
     * @param writeCellData
     */
    private void setWriteCellStyle(WriteCellData writeCellData, String orDefault) {
        //输出样式转换,颜色值,默认黑色
        short orDefaultStyle = 0;

        //条件,满足条件则修改内容,可以叠加更多的条件,只要符合k-v规则,即比较k,填充v
        //因为这里是中文k 和 颜色索引,这里比较的就是中文,如果能保障k不重复,则k可以是数字、字符等,对应的v也就可以是数字、字符等,
        //这样就可以按照需求对单元格式进行一定的操作编辑
        //需要注意的是,这里用的转换之后的输出值进行的比较,有需要使用原始值的可以自行微调一下
        if (fontColorMap != null && fontColorMap.containsKey(orDefault)) {
            WriteFont writeFont = new WriteFont();
            WriteCellStyle writeCellStyle = new WriteCellStyle();
            orDefaultStyle = Short.parseShort(fontColorMap.getOrDefault(orDefault, ""));
            writeFont.setColor(orDefaultStyle);
            writeCellStyle.setWriteFont(writeFont);
            writeCellData.setWriteCellStyle(writeCellStyle);
        }
    }
}

1.这里面只是修改了部分直接引用字符的地方,将其使用字典值代替。
2.在作者原有的基础上,增加和调整了满足条件后,对字体颜色标记的功能。相关样式可以自己做调整,比如添加背景色等。
逻辑也跟简单,就是拿到转换之后的值,通过这个值,与注解传递的值进行比较,满足条件则添加样式。
因为添加样式只存在于导出的时候,所以只需要关注导出的方法体即可。多选的我暂时没有场景,没有添加,实际逻辑是一样的。

4.测试实体类(因为我懒。不是,要尊重作者! )

import com.alibaba.excel.annotation.ExcelProperty;
import com.example.test.excel.EasyExcelConvert;
import com.example.test.excel.EnumFiledConvert;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
/**
 * @Author 996
 * @Date 2024/3/20
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ExcelDto {
    @ExcelProperty(value = "姓名")
    private String name;
 
    @ExcelProperty(value = "性别",converter = EasyExcelConvert.class)
    @EnumFiledConvert(enumMap = "0|保密,1|男,2|女")
    private Integer sex;
 
    @ExcelProperty(value = "爱好",converter = EasyExcelConvert.class)
    @EnumFiledConvert(enumMap = "1|篮球,2|足球,3|乒乓球,4|羽毛球",, fontColorMap = "篮球|2",single = false)
    private String hobbies;
}

使用时,只需要 2个步骤 ,(1)在实体类上添加自定义注解,(2)在原生的 @ExcelProperty 注解中,指定自定义解析Convert。
这时导出,对应字段列的值,就会被替换成对应的数据项。
需要注意:
1.跟原作者不一样,这里多个字典值之间使用的还是逗号,但是k-v的映射关系使用的是竖线
2.这里的k-v不一定要符合现在的这种数字和中文的组合,只需要保证k-v分别为字符串,且内容不含逗号竖线即可。比如其他字典映射:Y|是     Y-1|特例1     N|bushi     是|正确的答案     只要符合对应的格式即可,更加灵活。
3.可以修改自定义注解中的符号,以调整对应的格式,但是需要注意,不是所有的都可以直接兼容,需要进行一定的转义,这一点肯定难不倒聪明的你。
4.注意第三个属性的注解,多加了fontColorMap,前面的是输出的值,可以对应enumMap里面的字典值转换,后面的是颜色索引,这里的2标识为红色,可以看org.apache.poi.ss.usermodel.IndexedColors; 中的IndexedColors.RED.getIndex()枚举,颜色索引很全。

基于以上字体颜色修改的逻辑,我们能够拿到所有输出的值的内容,包括原始值,那么我们就可以通过一系列的条件,来实现我们对某些特定内容的数据进行样式调整,包括但不限于字体调整、字体颜色调整、字体颜色调整、数据值调整、单元格背景颜色调整、单元格边框调整等等等等

5.输出

这个大家都会,这里摘一部分代码套用

//数据集合,这里是用的实体类
List<ClockCount> countList = new ArrayList<>();

ExcelWriter excelWriterCount = EasyExcel.write("文件完整路径,含后缀").build();
WriteSheet writeSheetCount = EasyExcel.writerSheet("表格中sheet名称").build();

//我这是用实体类进行的文件输出
writeSheetCount.setClazz(ClockCount.class);
//写出数据
excelWriterCount.write(countList , writeSheetCount);
excelWriterCount.finish();

执行导出即可完成。通过循环,或者针对同一文件名,相同sheet名称或者不相同名称,可以实现对同一表格相同sheet页或多个sheet页数据写出,这个就和原生一致了。

  • 32
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在使用EasyExcel时,有时会遇到一些数据类型在导出EasyExcel不支持的情况。为了解决这个问题,我们可以自定义转换器来手动注入。首先,在代码中导入需要的包,并创建一个自定义转换器类,比如CharConverter。在CharConverter类中,我们需要实现Converter接口,并重写其中的方法,如supportJavaTypeKey()和convertToExcelData()。在supportJavaTypeKey()方法中,我们需要指定该转换器支持的类型,比如Character类型。在convertToExcelData()方法中,我们可以自定义对Character类型数据的处理,例如将Character类型的值转换成String类型。接下来,我们需要将自定义转换器注册到EasyExcel中。在写操作时,我们可以通过调用registerConverter()方法,将自定义转换器注册到EasyExcel中。例如,在写操作的方法中,我们可以使用@RequestMapping注解指定路径和请求方法,并在方法内部通过EasyExcel.write()和.registerConverter()方法来注册转换器。具体的代码示例可以参考引用和引用。通过这样的方式,我们就可以在使用EasyExcel自定义转换器来处理不支持的数据类型。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [EasyExcel 自定义类型转换器](https://blog.csdn.net/weixin_45535519/article/details/130291453)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [EasyExcel 自定义类型转换器Converter3种加载方式(转换字段加载类型转换器导出时加载类型转换器、加载...](https://blog.csdn.net/qq_38974638/article/details/119295809)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CloverAn

如果文章对你有帮助,感谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值