为什么我在带有spring5的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约束冲突抛出Spring的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));
}
}

EDIT:我看到您将assignableTypesannotations都用于@ControllerAdvice异常处理程序。这使得Spring为所有@RestControllers注册一个异常处理程序。请尝试使用assignableTypesannotations

作为一种选项,您可以为不同的异常处理程序创建自定义注释。

下面的代码打印";一个";当提供给CCD_ 12的无效数据和"0"时;两个";当数据被发送到"/两个";。

@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");
}
}

只有当我在控制器中添加方法时,模型的javax注释样式验证才对我有效:

public class ApiController {
...
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<INErrors> handleConstraintViolation(MethodArgumentNotValidException exception) {
BindingResult result = exception.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return new ResponseEntity<>(processFieldErrors(fieldErrors), HttpStatus.BAD_REQUEST);
}
}

最新更新