一、概述
在利用Spring進(jin)行Web后臺開發(fa)時(shi),經常會遇到(dao)枚舉(ju)類型(xing)綁定問題(ti)。一般情況下,如(ru)果Spring接(jie)收到(dao)的(de)參(can)數值(zhi)為字(zi)符串類型(xing),Spring會根據枚舉(ju)的(de)值(zhi)與傳入(ru)的(de)字(zi)符串進(jin)行對應。假設如(ru)下枚舉(ju)
枚舉定義
public enum TestEnum {
FIRST(1,"第一個"),
SECOND(2,"第二個"),
THIRD(3,"第三個");
}
那么客戶端請求時,將參數(shu)值設置(zhi)成FIRST或SECOND。但是(shi)如果設置(zhi)的(de)(de)字符串(chuan)不是(shi)對應(ying)的(de)(de)就沒辦(ban)法完成映(ying)射。
二、枚舉與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();
}
}
通(tong)過(guo)(guo)重寫toString方(fang)(fang)法(fa),即(ji)可在(zai)轉JSON的時(shi)(shi)候返回code的String值,而不是(shi)FIRST這種字符串(chuan)(chuan)。通(tong)過(guo)(guo)在(zai)toString方(fang)(fang)法(fa)上注(zhu)解@JsonValue,可在(zai)JSON字符串(chuan)(chuan)轉對象時(shi)(shi)將code的值轉成枚舉,但是(shi)此方(fang)(fang)法(fa)只限于@RequestBody,返回值通(tong)過(guo)(guo)JSON格式(shi)返回時(shi)(shi)。如果是(shi)普通(tong)的@RequestParam將達不到效果。
三、Spring轉化器實現
1、定義枚舉接口
public interface BaseEnum {
Integer getCode();
}
2、定義(yi)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());
}
}
啟動項目后,不管是(shi)通過(guo)@RequestParam接(jie)收(shou)參數(shu)(shu),還是(shi)通過(guo)對象包裹接(jie)收(shou)參數(shu)(shu),都可以通過(guo)枚舉(ju)中(zhong)的code值映射。
@RequestMapping("/test-param")
public TestEnum testParam(@RequestParam("test")TestEnum testEnum){
}
@RequestMapping("/test-object")
public TestRequest testObject(TestRequest request){
}
但是(shi)還存(cun)在問題,通過(guo)@RequestBody接收(shou)參(can)數(shu)還是(shi)沒辦法做到(dao)映射,前端參(can)數(shu)傳code不生效,默(mo)認(ren)用的是(shi)枚舉的original或者枚舉的名稱(cheng)做映射。這個時候就可以結合上面的注解@JsonValue,即枚舉與(yu)JSON轉化時通過(guo)被注解的方法返回的值(zhi)進行。
@Override
@JsonValue
public String toString() {
return this.getCode().toString();
}
注解了@JsonValue后,也(ye)將枚(mei)舉類(lei)型(xing)(xing)的返回值統一成code的字符(fu)串。至(zhi)此(ci),不管使(shi)用什(shen)么方(fang)式(shi)進行傳(chuan)參,或者將枚(mei)舉類(lei)型(xing)(xing)返回,都是保持一致的code字符(fu)串,從而達成統一。