Spring boot枚举传参转换
在实际web开发项目中会用到枚举,本文章主要分析SpringBoot传参转换枚举, 主要包括SpringBoot传参转换枚举使用实例、应用技巧、基本知识点总结和需要注意事项,该技术对于Spring MVC同样适用。具体来讲可以归纳两种实现方式
- 可以基于Jackson自带枚举序列化方式进行转换;
- 基于Spring类型转换器方式来实现枚举传参转换;
以上两种方式都可以实现,只是方法一对于简单处理是可行,但是对于复杂或者全局处理就有局限性,推荐方法二, 本文主要解剖第二种实现方式
有时候,我们传参的时候,希望使用枚举类来当作参数,如下:
e.g :
public enum VipEnum {
YELLOW(1, "黄钻"),
RED(2, "红钻");
private Integer index;
private String value;
VipEnum(Integer index, String value) {
this.index = index;
this.value = value;
}
public Integer getIndex() {
return index;
}
public String getValue() {
return value;
}
}
我们期望的是这样,参数中传一个1 后台就自动转换为枚举类的VipEnum.YELLOW
@PostMapping("/vip")
public VipEnum convert(VipEnum vipEnum) {
return vipEnum;
}
实现Converter接口
基于需求,我们可以考虑适用Spring
的类型转换器,来实现此功能需求。 Spring
为我们提供了一个类型自动转换接口Converter<S, T>
,可以实现从一个Object转为另一个Object的功能。除了Converter接口之外。
-
接口
public interface Converter<S, T> { T convert(S source); }
-
实现
@Component @Slf4j public class PersonConverter implements Converter<String, VipEnum> { @Override public VipEnum convert(String value) { log.info("参数是: {}", value); return (VipEnum) PersonConverter.getEnum(VipEnum.class, value); } public static <T extends VipEnum> Object getEnum(Class<T> targerType, String source) { for (T enumObj : targerType.getEnumConstants()) { if (source.equals(String.valueOf(enumObj.getId()))) { return enumObj; } } return null; } }
至此,基本上完成功能需求。
注意:在Spring MVC和Spring Boot中,由于从客户端接收到的请求都被视为String类型,所以只能用String转枚举的converter
拓展
对于上述实现,存在如下局限性: 1.只能把所有类型都转换成字符串类型处理,这对于GET请求来说可以,但是对于POST这肯定是不行的; 2.项目中如果比较多的枚举需要转换,上述实现就不可取;
ConverterFactory接口
ConverterFactory的出现可以让我们统一管理一些相关联的Converter。顾名思义,ConverterFactory就是产生Converter的一个工厂,确实ConverterFactory就是用来产生Converter的。ConverterFactory接口的定义
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
可以看出 总共有 三个泛型S、R、T,其中:
- S表示原类型
- R表示目标类型
- T是类型R的一个子类
ConverterFactory相比converter的好处在于ConverterFactory可以将原类型转换成一组实现了相同接口类型的对象, 而Converter则只能转换成一种类型。
实现全局转换
-
声明一个接口,让需要转换的枚举去实现该接口
public interface IBaseEnum<T> { T getIndex(); } public enum VipEnum implements IBaseEnum<Integer> { HUANG(1, "黄钻"), HONG(2, "红钻"); private Integer index; private String value; VipEnum(Integer index, String value) { this.index = index; this.value = value; } @Override public Integer getIndex() { return index; } public String getValue() { return value; } } }
2.实现转化器工厂
-
实现索引值为整数类型;
@Slf4j @Component public class IntegerCodeToEnumConverterFactory implements ConverterFactory<Integer, IBaseEnum> { private static final Map<Class, Converter> CONVERTERS = Maps.newHashMap(); @Override public <T extends IBaseEnum> Converter<Integer, T> getConverter(Class<T> targetType) { Converter<Integer, T> converter = CONVERTERS.get(targetType); if (Objects.isNull(converter)) { converter = new IntegerToEnumConverter<>(targetType); CONVERTERS.put(targetType, converter); } return converter; } private static class IntegerToEnumConverter<T extends IBaseEnum> implements Converter<Integer, T> { private final Map<Integer, T> enumMap = Maps.newHashMap(); public IntegerToEnumConverter(Class<T> enumType) { T[] enums = enumType.getEnumConstants(); Arrays.stream(enums).forEach(p -> enumMap.put((Integer) p.getIndex(), p)); } @Override public T convert(Integer source) { T t = enumMap.get(source); if (Objects.isNull(t)) log.error("ERROR", new IllegalArgumentException("无法匹配对应的枚举类型")); return t; } } }
-
实现索引值为字符串类型;
@Slf4j @Component public class StringCodeToEnumConverterFactory implements ConverterFactory<String, IBaseEnum> { private static final Map<Class, Converter> CONVERTERS = Maps.newHashMap(); @Override public <T extends IBaseEnum> Converter<String, T> getConverter(Class<T> targetType) { Converter<String, T> converter = CONVERTERS.get(targetType); if (Objects.isNull(converter)) { converter = new StringToEnumConverter<>(targetType); CONVERTERS.put(targetType, converter); } return converter; } private static class StringToEnumConverter<T extends IBaseEnum> implements Converter<String, T> { private Map<String, T> enumMap = Maps.newHashMap(); public StringToEnumConverter(Class<T> enumType) { T[] enums = enumType.getEnumConstants(); Arrays.stream(enums).forEach(p -> enumMap.put(p.getIndex().toString(), p)); } @Override public T convert(String source) { T t = enumMap.get(source); if (Objects.isNull(t)) log.error("ERROR", new IllegalArgumentException("无法匹配对应的枚举类型")); return t; } } }
具体可以查看项目中com.zc.travel.converter.factory.StringCodeToEnumConverterFactory
类
3.配置以及注册转换器工厂类使之生效
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private IntegerCodeToEnumConverterFactory integerCodeToEnumConverterFactory;
@Resource
private StringCodeToEnumConverterFactory stringCodeToEnumConverterFactory;
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverterFactory(integerCodeToEnumConverterFactory);
registry.addConverterFactory(stringCodeToEnumConverterFactory);
}
}
经过上述实现可以在接口中传index值就可以实现转换。
来源:oschina
链接:https://my.oschina.net/VILLE/blog/4278118