searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Spring Controller接口枚举映射

2023-05-24 02:41:09
41
0
一、概述

在利用Spring进行Web后台开发时,经常会遇到枚举类型绑定问题。一般情况下,如果Spring接收到的参数值为字符串类型,Spring会根据枚举的值与传入的字符串进行对应。假设如下枚举

枚举定义

public enum TestEnum {
    FIRST(1,"第一个"),
    SECOND(2,"第二个"),
    THIRD(3,"第三个");
}

那么客户端请求时,将参数值设置成FIRST或SECOND。但是如果设置的字符串不是对应的就没办法完成映射。

二、枚举与Jackson结合

枚举的全部定义

public enum TestEnum {
    FIRST(1,"第一个"),
    SECOND(2,"第二个"),
    THIRD(3,"第三个");
    private Integer code;
    private String desc;
    TestEnum(Integer code,String desc){
        this.code = code;
        this.desc = desc;
    }
    @Override
    @JsonValue
    public String toString() {
        return this.getCode().toString();
    }
}

通过重写toString方法,即可在转JSON的时候返回code的String值,而不是FIRST这种字符串。通过在toString方法上注解@JsonValue,可在JSON字符串转对象时将code的值转成枚举,但是此方法只限于@RequestBody,返回值通过JSON格式返回时。如果是普通的@RequestParam将达不到效果。

三、Spring转化器实现

1、定义枚举接口

public interface BaseEnum {
    Integer getCode();
}

2、定义ConverterFactory

public class CommonEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
    private static final Map<Class,Converter> convertMap = new WeakHashMap<>();
    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        Converter result = convertMap.get(targetType);
        if(result == null){
            result = new IntegerStrToEnum<T>(targetType);
            convertMap.put(targetType,result);
        }
        return result;
    }
    class IntegerStrToEnum<T extends BaseEnum> implements Converter<String,T>{
        private final Class<T> enumType;
        private Map<String,T> enumMap = new HashMap<>();
        public IntegerStrToEnum(Class<T> enumType){
            this.enumType = enumType;
            T[] enums = enumType.getEnumConstants();
            for(T e : enums){
                enumMap.put(e.getCode() + "",e);
            }
        }
        @Override
        public T convert(String s) {
            T result = enumMap.get(s);
            if(result == null){
                throw new IllegalArgumentException("No element matches " + s);
            }
            return result;
        }
    }
}

3、将转化器工厂注入到WebMvc

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new CommonEnumConverterFactory());
    }
}

启动项目后,不管是通过@RequestParam接收参数,还是通过对象包裹接收参数,都可以通过枚举中的code值映射。

@RequestMapping("/test-param")
public TestEnum testParam(@RequestParam("test")TestEnum testEnum){
}
@RequestMapping("/test-object")
public TestRequest testObject(TestRequest request){ 
}

但是还存在问题,通过@RequestBody接收参数还是没办法做到映射,前端参数传code不生效,默认用的是枚举的original或者枚举的名称做映射。这个时候就可以结合上面的注解@JsonValue,即枚举与JSON转化时通过被注解的方法返回的值进行。

@Override
@JsonValue
public String toString() {
    return this.getCode().toString();
}

注解了@JsonValue后,也将枚举类型的返回值统一成code的字符串。至此,不管使用什么方式进行传参,或者将枚举类型返回,都是保持一致的code字符串,从而达成统一。

0条评论
0 / 1000
x****n
6文章数
0粉丝数
x****n
6 文章 | 0 粉丝