programing

제약 위반 변환 방법예외 500 오류에서 400개의 잘못된 요청까지?

muds 2023. 3. 7. 22:08
반응형

제약 위반 변환 방법예외 500 오류에서 400개의 잘못된 요청까지?

이 @NotNull과 같은 제약조건을 사용하고 컨트롤러에서

public User createUser(
            @Validated
            @RequestBody User user) {}

그것은 정말 멋진 400개의 예외와 세부사항을 제공한다.

그러나 다음과 같이 나만의 커스텀 검증기를 사용하는 경우:

public User createUser(
            @UserConstraint
            @RequestBody User user) {}

다음과 같은 500 서버 오류가 발생합니다.

javax.validation.ConstraintViolationException: createUser.user: Error with field: 'test35'
    at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:117) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69) ~[spring-security-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]

답장에 400개의 멋진 메시지를 받을 수 있는 방법이 있나요?

400 메시지는 Spring의 검증 JSON과 동일해야 합니다.

{
    "timestamp": "2019-10-30T02:33:15.489+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "Size.user.lastName",
                "Size.lastName",
                "Size.java.lang.String",
                "Size"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.lastName",
                        "lastName"
                    ],
                    "arguments": null,
                    "defaultMessage": "lastName",
                    "code": "lastName"
                },
                25,
                1
            ],
            "defaultMessage": "size must be between 1 and 25",
            "objectName": "user",
            "field": "lastName",
            "rejectedValue": "",
            "bindingFailure": false,
            "code": "Size"
        }
    ],
    "message": "Validation failed for object='user'. Error count: 1",
    "path": "/api/v1/users"
}

네, 작성 가능합니다.custom error handler응답 및 상태에도 원하는 내용을 추가할 수 있습니다.상태를 변경하는 간단한 방법은 다음과 같습니다.

1.- 심플한 변경 방법status언제ConstraintViolationException던집니다.

import javax.validation.ConstraintViolationException;

@ControllerAdvice
public class CustomErrorHandler {

    @ExceptionHandler(ConstraintViolationException.class)
    public void handleConstraintViolationException(ConstraintViolationException exception,
            ServletWebRequest webRequest) throws IOException {
        webRequest.getResponse().sendError(HttpStatus.BAD_REQUEST.value(), exception.getMessage());
    }
}    

2.- 사용자 지정 방식으로 응답할 경우ConstraintViolationException일어나다.

@ControllerAdvice
public class CustomErrorHandler {

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<CustomError> handleConstraintViolationException(ConstraintViolationException exception) {
        CustomError customError = new CustomError();
        customError.setStatus(HttpStatus.BAD_REQUEST);
        customError.setMessage(exception.getMessage());
        customError.addConstraintErrors(exception.getConstraintViolations());
        return ResponseEntity.badRequest().body(customError);
    }
}   

위의 솔루션으로는 원하는 결과를 얻을 수 없기 때문에 다음 링크에서 도움이 될 수 있습니다.https://sterl.org/2020/02/spring-boot-hateoas-jsr303-validation/

클래스 또는 메서드 요청 본문에 @Validated 주석이 붙어 있는 경우 Funny enough spring은 다르게 동작합니다.

즉, 클래스에서 500개의 오류가 발생할 수 있습니다.이미 수행한 것처럼 검증 주석을 메서드로 이동하면 일반 동작은 400이 됩니다.

간단히 말하면, 커스텀의 내용물 등을 갖추는 즉시 내용을 약간 조정할 필요가 있습니다.스프링과 마찬가지로 MethodArgumentNotValidException은 제약 위반이 아니라 MethodArgumentNotValidException 입니다.Spring은 이미 컨트롤러 어드바이스로서 예외입니다.

퀵 솔루션은 다음과 같습니다.

@Autowired
private MessageSource messageSource;

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public @ResponseBody Map<String, Object> handleConstraintViolation(ConstraintViolationException e, ServletWebRequest request) {
    // emulate Spring DefaultErrorAttributes
    final Map<String, Object> result = new LinkedHashMap<>();
    result.put("timestamp", new Date());
    result.put("path", request.getRequest().getRequestURI());
    result.put("status", HttpStatus.BAD_REQUEST.value());
    result.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase());
    result.put("message", e.getMessage());
    result.put("errors", e.getConstraintViolations().stream().map(cv -> SimpleObjectError.from(cv, messageSource, request.getLocale())));
    return result;
}

@Getter @ToString
static class SimpleObjectError {
    String defaultMessage;
    String objectName;
    String field;
    Object rejectedValue;
    String code;

    public static SimpleObjectError from(ConstraintViolation<?> violation, MessageSource msgSrc, Locale locale) {
        SimpleObjectError result = new SimpleObjectError();
        result.defaultMessage = msgSrc.getMessage(violation.getMessageTemplate(),
                new Object[] { violation.getLeafBean().getClass().getSimpleName(), violation.getPropertyPath().toString(),
                        violation.getInvalidValue() }, violation.getMessage(), locale);
        result.objectName = Introspector.decapitalize(violation.getRootBean().getClass().getSimpleName());
        result.field = String.valueOf(violation.getPropertyPath());
        result.rejectedValue = violation.getInvalidValue();
        result.code = violation.getMessageTemplate();
        return result;
    }
}

간단히, 주석을 단 메서드를 정의합니다.@ExceptionHandler주석이 달린 학급에서@ControllerAdvice:

@ControllerAdvice
public class YourControllerAdvice {

    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public void handleConstraintViolationException() {
    // Intentionally left blank
    }
}

주석이 달린 클래스@ControllerAdvice는 컨트롤러 수준에서 예외를 처리하기 위해 사용됩니다.

언급URL : https://stackoverflow.com/questions/58614373/how-to-convert-constraintviolationexception-500-error-to-400-bad-request

반응형