在项目中,对于一些用户的账号状态,通常使用枚举类型来表示,比如BaseStatus.ENABLE
和BaseStatus.DISABLE
表示禁用和正常。而在controller层,也是使用枚举类型来作为参数接收前端传递的信息。
public enum BaseStatus {
ENABLE(1, "正常"),
DISABLE(0, "禁用");
private Integer code;
private String name;
BaseStatus(Integer code, String name) {
this.code = code;
this.name = name;
}
public Integer getCode() {
return code;
}
public String getName() {
return name;
}
}
@Operation(summary = "根据ID修改后台用户状态")
@PostMapping("/updateStatusByUserId")
public Result updateStatusByUserId(@RequestParam Long id, @RequestParam BaseStatus status) {
LambdaUpdateWrapper<SystemUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SystemUser::getId, id);
updateWrapper.set(SystemUser::getStatus, status);
service.update(updateWrapper);
return Result.ok();
}
但是在实际使用时会报错,虽然SpringMVC
提供了常用类型的转换器,例如String
到Interger
、String
到Boolean
等等,其中也包括String
到枚举类型,但是String
到枚举类型的转换规则是默认是根据实例名称 ( "ENABLE
" ) 转换为枚举对象实例 ("BaseStatus.ENABLE
"),而前端传递的数字(1/2)是枚举对象实例的code属性而不是实例对象。
因此就会报错MethodArgumentTypeMismatchException
。
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam com.lease.model.enums.BaseStatus] for value '1'
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:129)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:73)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:729)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:125)
... 47 more
如果想实现code属性到枚举对象实例的转换,就需要自定义Converter
@Component
public class StringToBaseStatusConverter implements Converter<String, BaseStatus> {
@Override
public BaseStatus convert(String code) {
for (BaseStatus value : BaseStatus.values()) {
if (value.getCode().equals(Integer.valueOf(code))) {
return value;
}
}
throw new IllegalArgumentException("code非法");
}
}
如果项目中存在其他的枚举类型,为了能动态的寻找枚举实例,可以先定义一个接口,让需要转换的枚举类型实现该接口,然后利用ConverterFactory
来自动选择枚举类型。
public interface BaseEnum {
Integer getCode();
String getName();
}
public enum BaseStatus implements BaseEnum {
ENABLE(1, "正常"),
DISABLE(0, "禁用");
@EnumValue
@JsonValue
private Integer code;
private String name;
BaseStatus(Integer code, String name) {
this.code = code;
this.name = name;
}
@Override
public Integer getCode() {
return this.code;
}
@Override
public String getName() {
return this.name;
}
}
@Component
public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
// Base
@Override
public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
return new Converter<String, T>() {
@Override
public T convert(String code) {
T[] enumConstants = targetType.getEnumConstants();
for (T enumConstant : enumConstants){
if(enumConstant.getCode().equals(Integer.valueOf(code))){
return enumConstant;
}
}
throw new IllegalArgumentException("code: " + code + "非法");
}
};
}
}
别忘记在WebMvcConfiguration进行注册
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Resource
private StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory;
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverterFactory(this.stringToBaseEnumConverterFactory);
}
}
启动测试