• 从零搭建开发脚手架 SpringMvc中枚举类型参数的序列化和反序列化


    背景

    以下是我们一般的枚举类配合SpringMvc使用方式。

    枚举类如下

    public enum Distance {
        KILOMETER("km", 1000),
        MILE("miles", 1609.34),
        METER("meters", 1);
    
        private String unit;
        private final double meters;
    
        Distance(String unit, double meters) {
            this.unit = unit;
            this.meters = meters;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    实体类如下

    public class City {
        private String id;
        private Distance distance;
    
    • 1
    • 2
    • 3

    Controller如下

    -- /api/v1?distance=KILOMETER
    @GetMapping
    public void get(Distance distance) 
        
    -- /api/v1?distance=KILOMETER&id=1
    @GetMapping
    public void get(City city) 
        
    -- json
    {
      "id": "1",
      "distance": "KILOMETER"
    }
    @PostMapping
    public void post(@RequestBody City city)
        
    -- 反序列化    
    @GetMapping
    public City get()
    -- json    
    {
      "id": "1",
      "distance": "KILOMETER"
    }    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    默认所有的参数和响应都是大写的字符串枚举名称

    优化

    我们想自定义序列化和反序列化字段,例如使用unit或者meters属性。

    针对普通请求参数

    -- /api/v1?distance=KILOMETER
    @GetMapping
    public void get(Distance distance) 
    
    -- /api/v1?distance=KILOMETER&id=1
    @GetMapping
    public void get(City city) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1. 定义IEnum接口

    public interface IEnum<T extends Serializable> {
        T getValue();
    }
    
    • 1
    • 2
    • 3

    2.基于SpringMvc的Converter实现StringToEnum转换

    public class StringToEnumConvertFactory implements ConditionalGenericConverter {
        @Override
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            return IEnum.class.isAssignableFrom(targetType.getObjectType()) && sourceType.getObjectType() == String.class;
        }
        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            IEnum[] enums = (IEnum[]) targetType.getObjectType().getEnumConstants();
            for (IEnum anEnum : enums) {
                if (Objects.equals(anEnum.getValue(), source)) {
                    return anEnum;
                }
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.把转换器注册到SpringMvc

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringToEnumConvertFactory());
        }    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.自定义枚举实现定义IEnum接口

    public enum Distance implements IEnum<String> {
        KILOMETER("km", 1000),
        MILE("miles", 1609.34),
        METER("meters", 1);
        private String unit;
        private final double meters;
    
        Distance(String unit, double meters) {
            this.unit = unit;
            this.meters = meters;
        }
        @Override // 这里选择转换的属性
        public String getValue() {
            return unit;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    实现效果如下

    -- /api/v1?distance=km
    -- /api/v1?distance=miles
    @GetMapping
    public void get(Distance distance) 
    
    -- /api/v1?distance=km&id=1
    @GetMapping
    public void get(City city) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    针对RequestBody参数

    -- json
    {
      "id": "1",
      "distance": "KILOMETER"
    }
    @PostMapping
    public void post(@RequestBody City city)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    直接在枚举的指定get方法使用@JsonValue注解即可。

    public enum Distance implements IEnum<String> {
        KILOMETER("km", 1000),
        MILE("miles", 1609.34),
        METER("meters", 1);
        private String unit;
        private final double meters;
    
        Distance(String unit, double meters) {
            this.unit = unit;
            this.meters = meters;
        }
        @Override
        @JsonValue // 这里配置
        public String getValue() {
            return unit;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    实现效果如下

    -- json
    {
      "id": "1",
      "distance": "km"
    }
    @PostMapping
    public void post(@RequestBody City city)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    针对枚举类型响应

    直接在get方法使用@JsonValue注解即可。跟上面方式一样

    实现效果如下

    -- 反序列化    
    @GetMapping
    public City get()
    -- json    
    {
      "id": "1",
      "distance": "km"
    }   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    更多Jackson序列化和反序列化参考:https://blog.csdn.net/hj_5346/article/details/127269700

    • @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    • @JsonValue
    • @JsonSerialize(using = DistanceSerializer.class)
    • @JsonProperty(“distance-in-km”)
    • @JsonCreator
    • @JsonDeserialize(using = CustomEnumDeserializer.class)
  • 相关阅读:
    RabbitMQ 的死信交换机和备份交换机
    lombok @Slf4j注解啥作用
    团队管理之高效开发基础认知
    NeurIPS 2023 | FedFed:特征蒸馏应对联邦学习中的数据异构
    通过玩游戏学会AWS
    金仓数据库KingbaseES Clusterware配置手册(搭建集群 )
    [运维|中间件] Apache APISIX使用笔记
    多边形内部水平方向近似最大矩形python实现
    openbmc开发39:webui开发—增加风扇控制页面
    问题问题问题
  • 原文地址:https://blog.csdn.net/abu935009066/article/details/128046190