我正在使用 Spring 创建一个 API,但是我在引入关于请求正文验证(的一部分)的自定义错误报告时遇到了一些麻烦。
当发生解析/验证错误时,我想将自定义响应返回给用户。
这适用于用 @Valid
注释的字段。以及像 @javax.validation.constraints.NotNull
这样的验证器通过使用自定义 ResponseEntityExceptionHandler
用 @ControllerAdvice
注释.
但是,如果在解析请求正文时抛出异常(甚至在验证运行之前),它就不起作用。在这种情况下,我会得到一个状态为 500 (Server Error)
的 html 错误页面
如何确保解析过程中的异常导致与我因验证失败而返回的(自定义)响应相同类型的响应?
我的端点代码如下所示:
@RequestMapping(value= "/endpoint"
produces = { "application/json" },
consumes = { "application/json" },
method = RequestMethod.POST)
default ResponseEntity<Object> postSomething(@Valid @RequestBody MyRequestBody requestData){
// ...
}
MyRequestBody 类如下所示:
@Validated
public class MyRequestData {
@JsonProperty("stringValue")
private String stringValue = null;
@NotNull
@Valid
public String getStringValue() {
return stringValue;
}
// ...
public enum EnumValueEnum {
VALUE_1("value 1"),
VALUE_1("value 2");
private String value;
EnumValueEnum(String value) {
this.value = value;
}
@Override
@JsonValue
public String toString() {
return String.valueOf(value);
}
@JsonCreator
public static EnumValueEnum fromValue(String text) {
if(text == null){
return null;
}
for (EnumValueEnum b : EnumValueEnum.values()){
if (String.valueOf(b.value).equals(text)) {
return b;
}
}
throw new HttpMessageNotReadableException("EnumValueEnum \"" + text + "\" does not exist");
}
}
@JsonProperty("enumValue")
private EnumValueEnum enumValue = null;
}
自定义验证错误处理(和报告)如下所示:
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class MyValidationHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// return status(BAD_REQUEST).body(new ValidationResponse(ex.getBindingResult().getFieldErrors()));
}
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// return status(BAD_REQUEST).body(new ValidationResponse((JsonMappingException) ex.getCause()));
}
}
在此代码中,如果用户使用不存在的枚举值发送请求,则会引发 HttpMessageNotReadableException。我想在某处捕获它并将其替换为与我所做的其他异常处理一致的自定义响应。我在哪里/如何做到这一点?
最佳答案
我找到了解决我自己问题的方法。
您实际上可以使用 Spring MVC 的正常异常处理:
使用 @ExceptionHandler
注释方法将使 Spring 尝试使用它来处理指定的异常类型(在注释的值字段或方法的参数中)。这个方法可以放在 Controller 中,甚至可以放在ResponseEntityExceptionHandler
我用于其他验证响应处理。
@ExceptionHandler
public ResponseEntity handle(HttpMessageConversionException e){
// return status(BAD_REQUEST).body(new ValidationResponse((JsonMappingException) e.getCause()));
}
请注意您处理哪种类型的异常:
这里的问题是解析时抛出的异常包含在(的某些子类型)中
JsonMappingException
反过来又被包裹在 HttpMessageConversionException
中.e instanceof HttpMessageConversionException
e.getCause() instanceof JsonMappingException
e.getCause().getCause() // == your original exception
@ExceptionHandler
因此应该接受HttpMessageConversionException
而不是最初抛出的异常(在我的情况下是 HttpMessageNotReadableException
)如果你写一个
@ExceptionHandler
它将不起作用只接受你原来的异常!
关于spring - 如何确保解析期间的异常导致与验证失败返回的(自定义)响应相同类型的响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52425015/