java - 为什么我在使用 spring 5 的 tomcat 9 中得到代码 400 响应而不是错误 json 对象?
问题描述
控制器:
@RestController
@RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
@Validated
public class ApiController {
@PostMapping(value = "/in",
consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<InitResponse> inPost(
@ApiParam(required = true) @Valid @RequestBody InRequest inRequest) {
LOG.info("inPost request was received = {}", inRequest);
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
异常处理程序:
@ControllerAdvice(assignableTypes = ApiController .class, annotations = RestController.class)
public class InExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<INErrors> handleConstraintViolation(ConstraintViolationException ex) {
LOG.info("handleConstraintViolation was trigerred");
INError INError = new INError(HttpStatus.BAD_REQUEST.toString(), ex.getLocalizedMessage());
return new ResponseEntity<>(new INErrors(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<INErrors> handleMethodArgumentConstraintViolation(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return new ResponseEntity<>(processFieldErrors(fieldErrors), HttpStatus.BAD_REQUEST);
}
}
如果 InRequest 具有 javax 验证约束内的所有字段,那么我会得到正确的代码,但是当字段与验证不匹配时,我只会得到 400 响应代码。定义了其他异常处理程序,但我已将断点放置在任何地方,并且没有触发任何内容。
我还添加了 log4j 属性:
log4j.logger.org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod=DEBUG,stdout
但这在调试时没有产生任何额外的输出。我还希望将 INErrors 对象发回,但它甚至没有输入两种处理方法中的任何一种。
解决方案
这是因为 Spring 的默认异常处理程序自己处理所有 WebMvc 的标准异常,然后将未处理的异常委托给用户定义的@ExceptionHandler
方法。
在您的情况下,@Valid
违反约束会引发MethodArgumentNotValidException
由ResponseEntityExceptionHandler#handleMethodArgumentNotValid
. 因此,要更改此异常的默认行为,您需要在@ControllerAdivce
.
@ControllerAdvice(assignableTypes = ApiController .class, annotations = RestController.class)
public class InExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return ResponseEntity.badRequest().body(processFieldErrors(fieldErrors));
}
}
编辑:我看到您同时使用assignableTypes
和annotations
用于@ControllerAdvice
异常处理程序。这使得 Spring 为所有@RestController
s 注册一个异常处理程序。尝试使用assignableTypes
或annotations
。
作为一个选项,您可以为不同的异常处理程序创建自定义注释。
以下代码在向“/two”提供无效数据时打印“one”,在/one
向“/two”发送数据时打印“two”。
@RestController
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface One {}
@RestController
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Two {}
@One
class ControllerOne {
@PostMapping("one")
String a(@RequestBody @Valid Data data) {
return data.value;
}
}
@Two
class ControllerTwo {
@PostMapping("two")
String a(@RequestBody @Valid Data data) {
return data.value;
}
}
@ControllerAdvice(annotations = One.class)
class HandlerOne extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
return ResponseEntity.badRequest().body("one");
}
}
@ControllerAdvice(annotations = Two.class)
class HandlerTwo extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
return ResponseEntity.badRequest().body("two");
}
}
推荐阅读
- java - 在战争中打包后资源中的文件的 FileNotFoundException
- ibm-cloud - 设置集群和工作节点 - 如何在 Windows 10 中设置 KUBECONFIG 变量?
- .net - .NET Framework MVC 和 Web Api Auth JWT
- python - 使用 Django ManyToMany 对称属性构建传递依赖
- php - 为什么 json_decode 输出总是为空?
- sql - SQL While 循环继续运行
- c# - 从单个函数“使用”多个 IDisposable
- python - Jupyter notebook和matplotlib(运行时警告):关闭后继续显示绘图
- swift - 在 iOS 12 中按下 pickerView 栏按钮时应用程序崩溃,但在 iOS 11 中没有
- jquery - 设置隐藏的下拉选择值会导致 iOS 11 Safari 中的页面重新加载