在我们的项目中,我们定义如下的枚举
public enum GenderEnum implements IEnum{
MALE(1),
FEMALE(2);
private Integer code;
GenderEnum(int code) {
this.code = code;
}
public static GenderEnum getByCode(int code) {
for (GenderEnum genderEnum : values()) {
if (genderEnum.code == code) {
return genderEnum;
}
}
return null;
}
}
我们希望在用于参数的类中使用这些枚举,例如
public class Param{
String id;
GenderEnum gender;
}
我们有像
这样的控制器@RestController
class MyController{
@PostMapping('/alink')
ResponseBean doSomething(@RequestBody Param param){
...
}
}
对于上述情况,当请求正文为
{"id":"L323", "gender":1}
我们希望
1
可以转换为枚举 MALE
一种解决方案是在
@JsonCreator
上添加 getByCode(int code)
。但在我们现有的项目中,存储库层在将枚举插入数据库之前将其转换为字符串值(MALE
或 FEMALE
),而不是 code
值。因此,如果我们在 @JsonCreator
上添加 getByCode(int code)
,我们在尝试从数据库检索枚举时会遇到错误。
如何让 mvc/controller 将输入的整数值转换为枚举而不影响存储层?
我看到了如下解决方案:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverterFactory(new EnumConverterFactory());
}
}
static class EnumConverterFactory implements ConverterFactory<Integer, IEnum> {
@Override
public <T extends IEnum> Converter<Integer, T> getConverter(Class<T> targetType) {
if (!targetType.isEnum()) {
throw new UnsupportedOperationException(targetType + "is not enum");
}
return new EnumConverter(targetType);
}
private static class EnumConverter<T extends IEnum> implements Converter<Integer, T> {
private final Class<T> enumType;
public EnumConverter(Class<T> enumType) {
this.enumType = enumType;
}
@Override
public T convert(Integer code) {
for (T t : enumType.getEnumConstants()) {
if (code.equals(t.getCode())) {
return t;
}
}
return null;
}
}
}
但是这个解决方案不起作用。调试时,我注意到参数的解析取决于 Jackson 的序列化(根据序号而不是代码值将整数转换为枚举),并且根本不涉及转换器。
那么,有什么解决办法吗?
您可以在控制器中声明用于特定类型参数的自定义映射的方法:
@InitBinder
public void initBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(GenderEnum.class,
new PropertyEditorSupport() {
@Override
public void setAsText(String value){
setValue(GenderEnum.getByCode(Integer.parseInt(value)));
}
});
}