Spring全局异常处理器无法捕获非法枚举值请求异常的解决方法
解决枚举参数非法值导致的400无响应体问题
当传入不在ExpType枚举范围内的值时,Jackson在反序列化请求体时会抛出InvalidFormatException,被Spring包装为HttpMessageNotReadableException。默认的ResponseEntityExceptionHandler处理该异常时仅返回400状态码,无响应体;而你的自定义handleGeneralException未触发,是因为该异常被父类的默认处理逻辑优先捕获。
正确的全局异常处理器实现
方式一:继承ResponseEntityExceptionHandler并重写指定方法
通过重写父类的handleHttpMessageNotReadable方法,替换默认处理逻辑,返回自定义响应体:
@ControllerAdvice public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler { @Override protected ResponseEntity<Object> handleHttpMessageNotReadable( HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request ) { String errorMessage = "请求参数格式错误"; Throwable rootCause = ex.getRootCause(); // 提取枚举非法值的具体错误信息 if (rootCause instanceof InvalidFormatException) { InvalidFormatException invalidFormatEx = (InvalidFormatException) rootCause; if (invalidFormatEx.getTargetType().isEnum()) { errorMessage = String.format( "无效的枚举值:%s,允许的值为:%s", invalidFormatEx.getValue(), Arrays.toString(invalidFormatEx.getTargetType().getEnumConstants()) ); } } // 自定义错误响应体 ErrorResponse errorResponse = new ErrorResponse(status.value(), errorMessage); return new ResponseEntity<>(errorResponse, headers, status); } // 自定义错误响应DTO public static class ErrorResponse { private int status; private String message; public ErrorResponse(int status, String message) { this.status = status; this.message = message; } // Getter & Setter public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } }
方式二:直接使用@ExceptionHandler捕获指定异常
如果不需要处理其他Spring MVC标准异常,可直接捕获HttpMessageNotReadableException:
@ControllerAdvice public class GlobalControllerExceptionHandler { @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity<ErrorResponse> handleEnumInvalidValueException(HttpMessageNotReadableException ex) { String errorMessage = "请求参数格式错误"; Throwable rootCause = ex.getRootCause(); if (rootCause instanceof InvalidFormatException) { InvalidFormatException invalidFormatEx = (InvalidFormatException) rootCause; if (invalidFormatEx.getTargetType().isEnum()) { errorMessage = String.format( "无效的枚举值:%s,允许的值为:%s", invalidFormatEx.getValue(), Arrays.toString(invalidFormatEx.getTargetType().getEnumConstants()) ); } } ErrorResponse errorResponse = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMessage); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } // 自定义错误响应DTO同上 }
关键说明
- 异常捕获逻辑:通过
getRootCause()获取Jackson抛出的原始异常InvalidFormatException,判断目标类型为枚举后,生成包含非法值和允许值的友好提示。 - 响应体自定义:通过
ErrorResponseDTO返回结构化的错误信息,解决原场景中无响应体的问题。
内容的提问来源于stack exchange,提问作者lm.
相关产品推荐
相关产品推荐

