WebDataBinder 前端到后端的枚举类型转换,Converter,ConverterFactory

时间:2024-7-18    作者:老大夫    分类: 尚庭公寓


下面介绍一下每个环节的类型转换原理

  • WebDataBinder枚举类型转换

    WebDataBinder依赖于Converter实现类型转换,若Controller方法声明的@RequestParam参数的类型不是StringWebDataBinder就会自动进行数据类型转换。SpringMVC提供了常用类型的转换器,例如StringIntegerStringDateStringBoolean等等,其中也包括String到枚举类型,但是String到枚举类型的默认转换规则是根据实例名称("APARTMENT")转换为枚举对象实例(ItemType.APARTMENT)。若想实现code属性到枚举对象实例的转换,需要自定义Converter,代码如下,具体内容可参考官方文档

    • web-admin模块自定义com.atguigu.lease.web.admin.custom.converter.StringToItemTypeConverter
    @Component
    public class StringToItemTypeConverter implements Converter<String, ItemType> {
        @Override
        public ItemType convert(String code) {
    
            for (ItemType value : ItemType.values()) {
                if (value.getCode().equals(Integer.valueOf(code))) {
                    return value;
                }
            }
            throw new IllegalArgumentException("code非法");
        }
    }
    • 注册上述的StringToItemTypeConverter,在web-admin模块创建com.atguigu.lease.web.admin.custom.config.WebMvcConfiguration,内容如下:
    @Configuration
    public class WebMvcConfiguration implements WebMvcConfigurer {
    
        @Autowired
        private StringToItemTypeConverter stringToItemTypeConverter;
    
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(this.stringToItemTypeConverter);
        }
    }

    但是我们有很多的枚举类型都需要考虑类型转换这个问题,按照上述思路,我们需要为每个枚举类型都定义一个Converter,并且每个Converter的转换逻辑都完全相同,针对这种情况,我们使用ConverterFactory接口更为合适,这个接口可以将同一个转换逻辑应用到一个接口的所有实现类,因此我们可以定义一个BaseEnum接口,然后另所有的枚举类都实现该接口,然后就可以自定义ConverterFactory,集中编写各枚举类的转换逻辑了。具体实现如下:

    • model模块定义com.atguigu.lease.model.enums.BaseEnum接口
    public interface BaseEnum {
        Integer getCode();
        String getName();
    }
    • 令所有com.atguigu.lease.model.enums包下的枚举类都实现BaseEnun接口

    • web-admin模块自定义com.atguigu.lease.web.admin.custom.converter.StringToBaseEnumConverterFactory

    @Component
    public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
        @Override
        public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
            return new Converter<String, T>() {
                @Override
                public T convert(String source) {
    
                    for (T enumConstant : targetType.getEnumConstants()) {
                        if (enumConstant.getCode().equals(Integer.valueOf(source))) {
                            return enumConstant;
                        }
                    }
                    throw new IllegalArgumentException("非法的枚举值:" + source);
                }
            };
        }
    }
    • 注册上述的ConverterFactory,在web-admin模块创建com.atguigu.lease.web.admin.custom.config.WebMvcConfiguration,内容如下:
    @Configuration
    public class WebMvcConfiguration implements WebMvcConfigurer {
    
        @Autowired
        private StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory;
    
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverterFactory(this.stringToBaseEnumConverterFactory);
        }
    }

    注意:

    最终采用的是ConverterFactory方案,因此StringToItemTypeConverter相关代码可以直接删除。

  • TypeHandler枚举类型转换

    Mybatis预置的TypeHandler可以处理常用的数据类型转换,例如StringIntegerDate等等,其中也包含枚举类型,但是枚举类型的默认转换规则是枚举对象实例(ItemType.APARTMENT)和实例名称("APARTMENT")相互映射。若想实现code属性到枚举对象实例的相互映射,需要自定义TypeHandler

    不过MybatisPlus提供了一个通用的处理枚举类型的TypeHandler。其使用十分简单,只需在ItemType枚举类的code属性上增加一个注解@EnumValue,Mybatis-Plus便可完成从ItemType对象到code属性之间的相互映射,具体配置如下。

    public enum ItemType {
    
      APARTMENT(1, "公寓"),
      ROOM(2, "房间");
    
      @EnumValue
      private Integer code;
      private String name;
    
      ItemType(Integer code, String name) {
          this.code = code;
          this.name = name;
      }
    }
  • HTTPMessageConverter枚举类型转换

    HttpMessageConverter依赖于Json序列化框架(默认使用Jackson)。其对枚举类型的默认处理规则也是枚举对象实例(ItemType.APARTMENT)和实例名称("APARTMENT")相互映射。不过其提供了一个注解@JsonValue,同样只需在ItemType枚举类的code属性上增加一个注解@JsonValue,Jackson便可完成从ItemType对象到code属性之间的互相映射。具体配置如下,详细信息可参考Jackson官方文档

    @Getter
    public enum ItemType {
    
      APARTMENT(1, "公寓"),
      ROOM(2, "房间");
    
      @EnumValue
        @JsonValue
      private Integer code;
      private String name;
    
      ItemType(Integer code, String name) {
          this.code = code;
          this.name = name;
      }
    }


扫描二维码,在手机上阅读

推荐阅读: