Skip to content

# 希望添加导入导出枚举类支持 #1006

Description

@MS-Jing

希望添加导入导出枚举类支持

我们有时候需要某个字段是枚举类型的,例如数据库存的是1 而真实的含义可能是正常,当我导入导出的时候 需要的是真实的含义。
如果目前我们可以这样来操作:
用户可以自定义一个枚举接口,那么所有的需要导入导出的枚举字段实现该接口

/**
 * @author luojing
 * @since 2026/8/11 10:33
 * The enumeration that implements this interface has the ability to import and export enumerations.
 */
public interface IEnum {

    String getLabel();
}

@AllArgsConstructor
@Getter
public enum UserStatus implements IEnum {

    NORMAL(1, "正常"),
    LOCKING(2, "锁定");


    private final Integer value;
    private final String desc;

    @Override
    public String getLabel() {
        return desc;
    }
}

再自定一个这个枚举类型的转换器

package cn.idev.excel.converters.enums;

import cn.idev.excel.converters.Converter;
import cn.idev.excel.enums.CellDataTypeEnum;
import cn.idev.excel.enums.IEnum;
import cn.idev.excel.metadata.GlobalConfiguration;
import cn.idev.excel.metadata.data.ReadCellData;
import cn.idev.excel.metadata.data.WriteCellData;
import cn.idev.excel.metadata.property.ExcelContentProperty;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luojing
 * @description: enum converter
 * @since 2026/8/11 10:36
 */
public class IEnumConverter implements Converter<IEnum> {

    private static final Map<Class<?>, List<IEnum>> enumCache = new HashMap<>();

    @Override
    public Class<?> supportJavaTypeKey() {
        return IEnum.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public WriteCellData<?> convertToExcelData(IEnum value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        if (value != null) {
            return new WriteCellData<>(value.getLabel());
        }
        return new WriteCellData<>();
    }

    @Override
    public IEnum convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        Class<?> type = contentProperty.getField().getType();
        if (!enumCache.containsKey(type)) {
            Object[] enumConstants = type.getEnumConstants();
            List<IEnum> iEnumList = Arrays.stream(enumConstants).map(enumConstant -> (IEnum) enumConstant).collect(Collectors.toList());
            enumCache.put(type, iEnumList);
        }
        List<IEnum> iEnumList = enumCache.getOrDefault(type, Collections.emptyList());
        for (IEnum iEnum : iEnumList) {
            if (iEnum.getLabel().equals(cellData.getStringValue())) {
                return iEnum;
            }
        }
        return null;
    }
}

最后在我们需要导出的时候,将导出的类字段上指名这个转换器

@Data
public static class UserInfo {
    /**
     * 用户名
     */
    @ExcelProperty("用户名")
    private String userName;

    /**
     * 用户状态  这里指名用IEnumConverter的转换器
     */
    @ExcelProperty(value = "用户状态", converter = IEnumConverter.class)
    private UserStatus userStatus;
}

这样在我们导出的时候就可以直接用了

    @Test
    public void testIEnumConverter() {
        String fileName = System.getProperty("user.dir") + "/iEnumConverter" + System.currentTimeMillis() + ".xlsx";

        // 写出枚举类型字段
        FastExcel.write(fileName)
            .head(UserInfo.class)
//            .registerConverter(new IEnumConverter())
            .sheet()
            .doWrite(testDataList());

        // 读取枚举类型字段
        List<UserInfo> list = FastExcel.read(fileName)
//            .registerConverter(new IEnumConverter())
            .head(UserInfo.class)
            .sheet()
            .doReadSync();
        System.out.println(list);
    }

但是

这并不通用,这意味着我每个枚举字段都需要指名@ExcelProperty(converter = IEnumConverter.class) 或者手动注册转换器registerConverter(new IEnumConverter())
而且我看了CustomSheetWriteHandler 如果我们可以新增这个特性,那么我们可以对枚举类型的字段导入导出做一个下拉框限制:

解决方案(需要提pr)

  • 修改ConverterKeyBuild#buildKey方法,让枚举字段可以映射到转换器:
public static ConverterKey buildKey(Class<?> clazz, CellDataTypeEnum cellDataTypeEnum) {
    Class<?> boxingClass = BOXING_MAP.get(clazz);
    if (boxingClass != null) {
        return new ConverterKey(boxingClass, cellDataTypeEnum);
    }
    if (clazz == IEnum.class || (clazz.isEnum() && IEnum.class.isAssignableFrom(clazz))) {
        // clazz equals IEnum.class or clazz is enum and IEnum is assignable from clazz
        return new ConverterKey(IEnum.class, cellDataTypeEnum);
    }
    return new ConverterKey(clazz, cellDataTypeEnum);
}
  • IEnumConverter 注册到DefaultConverterLoader
  • 再次启动,无需每个枚举字段指名转换器和无需手动注册枚举转换器
  @Test
  public void testIEnumConverter() {
      String fileName = System.getProperty("user.dir") + "/iEnumConverter.xlsx";

      // 写出枚举类型字段
      FastExcel.write(fileName)
          .head(UserInfo.class)
          .sheet()
          .doWrite(testDataList());

      // 读取枚举类型字段
      List<UserInfo> list = FastExcel.read(fileName)
          .head(UserInfo.class)
          .sheet()
          .doReadSync();
      System.out.println(list);
  }

Originally posted by @MS-Jing in #1005

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions