SpringBoot实战:枚举类型转换问题

1.在controller层中完成service注入

2.调用业务层进行查询所有房间类型标签 

@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {

    @Autowired
    private LabelInfoService service;

    @Operation(summary = "(根据类型)查询标签列表")
    @GetMapping("list")
    public Result<List<LabelInfo>> labelList(@RequestParam(required = false) ItemType type) {
        //添加查询过滤条件
        LambdaQueryWrapper<LabelInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //type类型不为空,获取该类型的所有信息,由于涉及类型转换,需要手动配置converter
        lambdaQueryWrapper.eq(type != null, LabelInfo::getType, type);
        List<LabelInfo> list = service.list(lambdaQueryWrapper);
        return Result.ok(list);
    }

 转换问题

上述接口的功能是根据type(公寓/房间),查询标签列表。由于这个type字段在数据库、实体类、前后端交互的过程中有多种不同的形式,因此在请求和响应的过程中,type字段会涉及到多次类型转换。

数据库中type类型

+-------------+--------------+
| Field       | Type         |
+-------------+--------------+
| id          | bigint       |
| type        | tinyint      |
| name        | varchar(255) |
| create_time | timestamp    |
| update_time | timestamp    |
| is_deleted  | tinyint      |
+-------------+--------------+

 实体类中type字段为ItemType类型

@Schema(description = "标签信息表")
@TableName(value = "label_info")
@Data
public class LabelInfo extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "类型")
    @TableField(value = "type")
    private ItemType type;

    @Schema(description = "标签名称")
    @TableField(value = "name")
    private String name;
}

ItemType枚举类

public enum ItemType {

    APARTMENT(1, "公寓"),
    ROOM(2, "房间");

    private Integer code;
    private String name;

    ItemType(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}

前后端数据交互中type类型为数字

 数据类型转换过程及原理

`WebDataBinder`依赖于[`Converter`]实现类型转换,若Controller方法声明的`@RequestParam`参数的类型不是`String`,`WebDataBinder`就会自动进行数据类型转换。SpringMVC提供了常用类型的转换器,例如`String`到`Integer`、`String`到`Date`,`String`到`Boolean`等等,其中也包括`String`到枚举类型,但是`String`到枚举类型的默认转换规则是根据实例名称("APARTMENT")转换为枚举对象实例(ItemType.APARTMENT)。若想实现`code`属性到枚举对象实例的转换,需要自定义`Converter

WebDataBinder枚举类型转换

方法一:

步骤1、自定义Converter实体类实现Converter接口,并重写接口的方法

步骤2、自定义WebMvcConfiguration实体类实现WebMvcConfiguration接口,并重写addFormatters方法,在方法内将定义的Converter实体类添加到容器中

//自定义converter,完成枚举类型向string类型转换
@Component
public class StringToItemTypeConverter implements Converter<String, ItemType> {
    @Override
    public ItemType convert(String source) {

        //获取所有的ItemType枚举类型
        ItemType[] values = ItemType.values();
        for (ItemType itemType : values) {
            if (itemType.getCode().equals(Integer.valueOf(source))) {
                return itemType;
            }
        }

        throw new IllegalArgumentException("code非法");
    }
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Autowired
    private StringToItemTypeConverter converter;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(this.converter);
    }
}

局限性

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

 方法二:

 步骤一:实现接口ConverterFactory接口,并重写getConverter方法,由该方法实现所有子类枚举类型转换

 步骤二:自定义WebMvcConfiguration实体类实现WebMvcConfiguration接口,并重写addFormatters方法,在方法内将定义的ConverterFactory实体类添加到容器中

//完成String向BaseEnum转换,当String需要向BaseEnum的子类进行转换时,
//ConverterFactory会自动调用getConverter方法,并将需要转换的子类传入,此时可通过字节码加载所有的枚举常量进行比较
@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) {
                T[] enumConstants = targetType.getEnumConstants();
                for (T enumConstant : enumConstants) {
                    if (enumConstant.getCode().equals(Integer.parseInt(source))) {
                        return enumConstant;
                    }
                }
                throw new IllegalArgumentException("code:" + source + "非法");
            }
        };
    }
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Autowired
    private StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(stringToBaseEnumConverterFactory);
    }
}

TypeHandler枚举类型转换

Mybatis预置的`TypeHandler`可以处理常用的数据类型转换,例如`String`、`Integer`、`Date`等等,其中也包含枚举类型,但是枚举类型的默认转换规则是枚举对象实例(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`属性之间的互相映射。

@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;
    }
}

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

食懵你啊

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值