您如何保留Spring的内置REST Response JSON正文和@ControllerAdvise(和@RestControllerAdvise)类?

2022-09-03 15:47:54

在 Spring 4.x 中,如果使用扩展的 (or ),则对于标记为 的参数,默认情况下不再返回具有美观且信息丰富的 JSON 响应正文的默认异常处理。@RestControllerAdvise@ControllerAdviceResponseEntityExceptionHandler@Valid

在使用基于时,如何返回默认的 JSON 正文?ResponseEntityExceptionHandler@RestControllerAdvice

下面是一个描述这个问题的简单但完整的示例。使用这些类:

@RestController
class CarsController {

  @PostMapping("/cars")
  public void createCar(@RequestBody @Valid Car car) {
    System.out.println("Creating " + car);
    throw new WhateverException();
  }

  @ExceptionHandler(WhateverException.class)
  @ResponseStatus(HttpStatus.EXPECTATION_FAILED)
  public void handleWhateverException(){
    System.out.println("Handling a WhateverException.");
  }

}

class Car {

  @NotNull
  private String make;

  @NotNull
  private String model;

  ...getter/setters omitted for brevity...
}

class WhateverException extends RuntimeException {}

如果您提交一个POST/cars

{
    "make": "BMW"
}

它以 a 和以下正文进行响应:400

{
  "timestamp": 1491020374642,
  "status": 400,
  "error": "Bad Request",
  "exception": "org.springframework.web.bind.MethodArgumentNotValidException",
  "errors": [
    {
      "codes": [
        "NotNull.car.model",
        "NotNull.model",
        "NotNull.java.lang.String",
        "NotNull"
      ],
      "arguments": [
        {
          "codes": [
            "car.model",
            "model"
          ],
          "arguments": null,
          "defaultMessage": "model",
          "code": "model"
        }
      ],
      "defaultMessage": "may not be null",
      "objectName": "car",
      "field": "model",
      "rejectedValue": null,
      "bindingFailure": false,
      "code": "NotNull"
    }
  ],
  "message": "Validation failed for object='car'. Error count: 1",
  "path": "/cars"
}

但是,如果将异常处理方法移动到它自己的类,则标记为 ,该类从如下所示扩展:@RestControllerAdviceResponseEntityExceptionHandler

@RestControllerAdvice
class RestExceptionHandler extends ResponseEntityExceptionHandler {

  @ExceptionHandler(WhateverException.class)
  @ResponseStatus(HttpStatus.EXPECTATION_FAILED)
  public void handleWhateverException(WhateverException e, HttpServletRequest httpServletRequest) {
    System.out.println("Handling a WhateverException.");
  }

}

你会得到一个空的 body,这是由提供一个方法 () 引起的,该方法在 body 为 的地方构建一个响应。400ResponseEntityExceptionHandlerhandleMethodArgumentNotValid(..)null

您将如何更改此类以触发发生的原始处理,该处理提供一个 JSON 正文,描述为什么提交的请求无效?@RestControllerAdvice


答案 1

怎么样?

   @RestControllerAdvice
    class RestExceptionHandler {

      @ExceptionHandler(org.springframework.validation.BindException.class)
      public ResponseEntity<String> handleBindException(org.springframework.validation.BindException e) {
         return ResponseEntity.badRequest().body(e.getMessage());
      }
   }

当失败时,它会抛出BindException。你可以这样处理它。或者你可以这样做,这将给你完全相同的回应,就像之前抛出的一样。@Validthrow e


答案 2

一种方法是,对我有用的是不要扩展ResponseEntityExceptionHandler

因此,结果类将如下所示:

@RestControllerAdvice
class RestExceptionHandler {

  @ExceptionHandler(WhateverException.class)
  @ResponseStatus(HttpStatus.EXPECTATION_FAILED)
  public ResponseEntity<String> handleWhateverException(WhateverException e, HttpServletRequest httpServletRequest) {
    System.out.println("Handling a WhateverException.");
    return new ResponseEntity(...);
  }    
}

但另请参阅以下内容:模糊@ExceptionHandler方法映射为[类 org.springframework.web.bind.MethodArgumentNotValidException]


推荐