programing

@ControllerAdvision(및 @RestControllerAdvision) 클래스가 있는 Spring의 내장 REST Response JSON 본문을 어떻게 유지합니까?

powerit 2023. 6. 22. 22:31
반응형

@ControllerAdvision(및 @RestControllerAdvision) 클래스가 있는 Spring의 내장 REST Response JSON 본문을 어떻게 유지합니까?

Spring 4.x에서 다음을 사용할 경우@RestControllerAdvise(또는)@ControllerAdvice) 확장됩니다.ResponseEntityExceptionHandler친절하고 유익한 JSON 응답 본문을 사용하는 기본 예외 처리는 다음과 같이 표시된 인수에 대해 더 이상 기본적으로 반환되지 않습니다.@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"
}

다음과 같이 응답합니다.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"
}

그러나 예외 처리 방법을 해당 클래스로 이동할 경우 표시됨으로 표시됩니다.@RestControllerAdvice에서 확장된.ResponseEntityExceptionHandler예를 들어 다음과 같습니다.

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

}

당신은 받을 것입니다.400때문에 생긴 빈 몸으로.ResponseEntityExceptionHandler방법 제공(handleMethodArgumentNotValid(..)), 신체가 있는 곳에 반응을 구축합니다.null.

이것을 어떻게 바꾸시겠습니까?@RestControllerAdvice클래스는 발생하는 원래 처리를 트리거합니다. 이 클래스는 제출된 요청이 유효하지 않은 이유를 설명하는 JSON 본문을 제공합니까?

당신은 봄의 행동을 모방할 수 있습니다.@ControllerAdvice연장의ResponseEntityExceptionHandler:

@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body,
                             HttpHeaders headers, HttpStatus status, WebRequest request) {
    if (body == null) {
        body = ImmutableMap.builder()
                   .put("timestamp", LocalDateTime.now().atZone(ZoneId.systemDefault()).toEpochSecond())
                   .put("status", status.value())
                   .put("error", status.getReasonPhrase())
                   .put("message", ex.getMessage())
                   .put("exception", ex.getClass().getSimpleName())  // can show FQCN like spring with getName()
                   .put("path", ((ServletWebRequest)request).getRequest().getRequestURI())
                   .build();
    }
    return super.handleExceptionInternal(ex, body, headers, status, request);
}

*ImmutableMap구아바가 필요합니다.

**LocalDateTimeJava8이 필요합니다.

이건 어때?

   @RestControllerAdvice
    class RestExceptionHandler {

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

언제@Valid실패하면 BindException이 느려집니다.이런 식으로 처리할 수 있습니다.아니면 그냥 할 수 있습니다.throw e당신에게 아까 던져진 것과 똑같은 반응을 줄 것입니다.

한 가지 접근 방식은 확장하지 않는 것입니다.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(...);
  }    
}

그러나 이 항목도 참조하십시오.[class org.springframework.web.bind]에 대해 매핑된 모호한 @ExceptionHandler 메서드입니다.메서드 인수 NotValidException]

저는 같은 문제에 직면했습니다. 문제를 디버깅하는 데 많은 시간을 소비한 후 잭슨이 제대로 역직렬화하지 않고 있다는 것을 발견했습니다.ErrorResponse물건.

이는 정의된 필드에 대한 게터와 세터를 추가하지 않았기 때문입니다.ErrorResponse물건.생성자를 사용하여 필드를 초기화하고 있었는데 해당 필드에 대해 정의된 게터와 세터가 없습니다.

솔루션(빈 차체용):

그래서 업데이트할 때ErrorResponse에서의 반대.

import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;

@JsonRootName("error")
public class ErrorResponse {

  private String message;
  private List<String> details;

  public ErrorResponse(String message, List<String> details) {
    this.message = message;
    this.details = details;
  }
}

게터와 세터가 있는 다음 사람에게.

import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;

@JsonRootName("error")
public class ErrorResponse {

  private String message;
  private List<String> details;

  public ErrorResponse(String message, List<String> details) {
    this.message = message;
    this.details = details;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  public List<String> getDetails() {
    return details;
  }

  public void setDetails(List<String> details) {
    this.details = details;
  }
}

잭슨은 이제 역직렬화하고 있습니다.ErrorResponse연쇄 살인범의 시체를 찾고 있어요

언급URL : https://stackoverflow.com/questions/43153362/how-do-you-retain-springs-built-in-rest-response-json-body-with-a-controllerad

반응형