情景
在一个请求中有一个参数 range ,可以选择的有 week month quarter year 四个。为了不让 magic 变量漫天飞,我把他变成了一个枚举类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Getter public enum RangeEnum{
WEEK("week"), MONTH("month"), QUARTER("quarter"), YEAR("year");
private String value;
RangeEnum(String value) { this.value = value; }
}
|
Controller 中
1 2 3 4 5
| @GetMapping(value = "/list") public GenericResponse getXXList( @RequestParam(value = "range") RangeEnum range) { }
|
但是这样写,这个 controller 只能接收 WEEK,MONTH 等等,一旦出现 week 这样的参数是无法处理的。
解决
所以我们可以写一个 convertor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import org.springframework.core.convert.converter.Converter;
class StringToRangeEnumConverter implements Converter<String, RangeEnum> {
private Map<String, RangeEnum> enumMap = new HashMap<>();
StringToRangeEnumConverter() { for(RangeEnum e : RangeEnum.values()) { enumMap.put(e.getValue(), e); } }
@Override public RangeEnum convert(String source) {
RangeEnum result = enumMap.get(source); if (result == null) { throw new IllegalArgumentException("No element matches " + source); } return result; } }
|
这样问题又来了,如果有很多个枚举类,那我就要写很多了 convertor 了啊。
所以我们引入了一个 ConverterFactory
首先有一个 BaseEnum
1 2 3
| public interface BaseEnum { String getValue(); }
|
其他的枚举类实现这个借口就可以了,然后我们开始写 ConverterFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.ConverterFactory;
import java.util.HashMap; import java.util.Map;
public class StringToEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
private static final Map<Class, Converter> converterMap = new HashMap<>();
@Override public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) { Converter<String, T> converter = converterMap.get(targetType); if(converter == null) { converter = new StringToEnumConverter<>(targetType); converterMap.put(targetType, converter); } return converter; }
class StringToEnumConverter<T extends BaseEnum> implements Converter<String, T> {
private Map<String, T> enumMap = new HashMap<>();
StringToEnumConverter(Class<T> enumType) { T[] enums = enumType.getEnumConstants(); for(T e : enums) { enumMap.put(e.getValue(), e); } }
@Override public T convert(String source) {
T t = enumMap.get(source); if (t == null) { throw new IllegalArgumentException("No element matches " + source); } return t; } } }
|
写完了之后还不行,还需要在 spring 中注册这个 ConverterFactory 为什么要注册呢,这个地方我还不会,以后来填坑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import org.springframework.boot.SpringBootConfiguration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@SpringBootConfiguration public class WebMvcConfig implements WebMvcConfigurer {
@Override public void addFormatters(FormatterRegistry registry) { registry.addConverterFactory(new StringToEnumConverterFactory()); } }
|
这样以后我们就可以传参数 week month 等等了,如果传入了别的参数,就会抛出异常,异常的处理可以用全局的异常处理,这部分以后来填坑