Spring中如何处理@RequestBody传入错误枚举的异常?
问题描述
在Spring项目中,通过@RequestBody接收枚举类型时,传入正确值功能正常,但传入错误值会直接返回400状态码。我尝试实现了一个Converter来处理,但没有效果:
@Component public class EventTypeConverter implements Converter<String, EventType> { @Override public EventType convert(String s) { return EventType.valueOf(s.toUpperCase()); } }
我不想先接收String再手动转换处理异常,希望通过@ExceptionHandler来统一处理枚举转换异常,或者有其他更简洁的方案。我的枚举定义如下:
public enum EvenType { // 枚举实例... @Getter Character type; EvenType(Character type) { this.type = type; } public static EvenType of(String eventType) { return EvenType.valueOf(eventType); } }
解决方案
一、用@ExceptionHandler统一处理枚举转换异常
Spring反序列化@RequestBody中的枚举失败时,会抛出HttpMessageNotReadableException,其根源是枚举valueOf方法抛出的IllegalArgumentException。你可以通过全局异常处理器捕获该异常,自定义返回内容:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity<Map<String, String>> handleEnumConvertError(HttpMessageNotReadableException e) { Throwable rootCause = e.getRootCause(); if (rootCause instanceof IllegalArgumentException && rootCause.getMessage().contains("No enum constant")) { Map<String, String> errorResp = new HashMap<>(); errorResp.put("code", "INVALID_ENUM"); errorResp.put("message", "传入的枚举值非法,请检查参数"); return new ResponseEntity<>(errorResp, HttpStatus.BAD_REQUEST); } // 处理其他请求格式错误 Map<String, String> defaultError = new HashMap<>(); defaultError.put("code", "REQUEST_FORMAT_ERROR"); defaultError.put("message", "请求格式不符合要求"); return new ResponseEntity<>(defaultError, HttpStatus.BAD_REQUEST); } }
该方式能统一捕获所有枚举类型的转换错误,无需在每个接口单独处理。
二、修复Converter无效问题
你之前实现的Converter<String, EventType>仅适用于URL参数的类型转换,而@RequestBody的反序列化依赖Jackson的机制,因此该Converter不起作用。要处理RequestBody中的枚举反序列化,需自定义Jackson反序列化器:
public class EventTypeDeserializer extends StdDeserializer<EvenType> { protected EventTypeDeserializer() { super(EvenType.class); } @Override public EvenType deserialize(JsonParser parser, DeserializationContext context) throws IOException { String inputValue = parser.getText().trim().toUpperCase(); try { return EvenType.valueOf(inputValue); } catch (IllegalArgumentException e) { // 可抛出自定义异常,或根据业务返回默认枚举值 throw new IOException("非法事件类型:" + inputValue, e); } } }
在枚举类上添加注解指定该反序列化器:
@JsonDeserialize(using = EventTypeDeserializer.class) public enum EvenType { // 枚举实例... @Getter Character type; EvenType(Character type) { this.type = type; } public static EvenType of(String eventType) { return EvenType.valueOf(eventType); } }
当传入错误值时,Jackson会调用自定义反序列化器,抛出的异常可被全局异常处理器捕获并返回自定义信息。
三、优化枚举的of方法结合@JsonCreator
若不想自定义反序列化器,可修改枚举的of方法并添加@JsonCreator注解,指定Jackson反序列化时调用该方法:
public enum EvenType { // 枚举实例... @Getter Character type; EvenType(Character type) { this.type = type; } @JsonCreator public static EvenType of(String eventType) { try { return EvenType.valueOf(eventType.toUpperCase()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("无效的事件类型:" + eventType); } } }
@JsonCreator会引导Jackson使用该静态方法完成反序列化,抛出的异常同样会被全局异常处理器捕获处理。
内容的提问来源于stack exchange,提问作者gs97ahn
相关产品推荐
相关产品推荐

