[Spring] validation

yoon·2024년 1월 11일

spring-boot

목록 보기
7/41
post-thumbnail

beanvalidation
https://beanvalidation.org/2.0/spec/

✅ annotation

  • @Size : 문자 길이 측정, int 불가
  • @NotNull : null 불가
  • @NotEmpty : null, ""불가
  • @NotBlank: null,""," " 불가
  • @Pattern: 정규식 적용
  • @Max @Min : 최대값/최소값
  • @AssertTrue/False : 별도 logic 적용
  • @Past @PastOrPresent @Future @FutureOrPresent
    : 날짜체크 (과거, 오늘or과거, 미래, 오늘or미래)

✔ 사용하기

1. 의존성 추가하기

 implementation 'org.springframework.boot:spring-boot-starter-validation'

2. annotation 달아주기

//controller
 @PostMapping("")
    public Api<UserRegisterRequest> register(
            @Valid
            @RequestBody
            Api<UserRegisterRequest> userRegisterRequest
    ){...}

//model
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class UserRegisterRequest {

    @NotBlank
    private String name;
    
    @NotNull
    @Min(1)
    @Max(100)
    private Integer age;
}

이 상태에서 validate 에러가 발생하면 서버의 terminal에만 확인할 수 있다.
클라이언트에게 전달하려면 아래의 방법을 적용한다.

✔ client측에 에러 전달하기

1. BindingResult : 여러 상태값을 가져올 수 있다.

@Slf4j
@RestController
@RequestMapping("/api/user")
public class UserApiControllerValidate {
    @PostMapping("")
//    public Api<UserRegisterRequest> register(
    // error에 body가 없기때문에 UserRegisterRequest 반환못함
    public Api<? extends Object> register(
            @Valid
            @RequestBody
            Api<UserRegisterRequest> userRegisterRequest,
            BindingResult bindingResult // 에러 잡기 1 . valid실행결과를 binding result에 담아줌
    ){
        log.info("init : {}",userRegisterRequest);

        if(bindingResult.hasErrors()){ //에러가 발생했다면
            var errorMessageList = bindingResult.getFieldErrors().stream()
                    .map(it->{
                        var format = "%s :{ %s } 은 %s";
                        //                                   어떤 필드에서 어떤 값이 거절당했는지, 디폴트 메세지 출력
                        var message = String.format(format, it.getField(),it.getRejectedValue(),it.getDefaultMessage());
                        return message;
                    }).collect(Collectors.toList());

            var error = Api.Error.builder()
                    .errorMessage(errorMessageList)
                    .build();

            var errorResponse = Api.builder()
                    .resultCode(String.valueOf(HttpStatus.BAD_REQUEST.value()))
                    .resultMessage(HttpStatus.BAD_REQUEST.getReasonPhrase())
                    .error(error)
                    .build();
            return errorResponse;
        }
        var body = userRegisterRequest.getData();
        Api<UserRegisterRequest> response =  Api.<UserRegisterRequest>builder()
                .resultCode(String.valueOf(HttpStatus.OK.value()))
                .resultMessage(HttpStatus.OK.getReasonPhrase())
                .data(body)
                .build();
        return response;
    }
}

🔺 result_code = 400인데 전체 status_code는 200으로 전달됨

public ResponseEntity<Api<? extends Object>> register(

위와 같이 ResponseEntiy로 감싸서 sataus_code를 지정해줄 수 있음
하지만 검증 코드가 너무 길어지고 복잡해짐

2. Exception Handler로 넘겨준다.

@Slf4j
@RestControllerAdvice
public class ValidationExceptionHandler {
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResponseEntity<Api> validateException(
            MethodArgumentNotValidException e
    ){
        log.error("",e);

            var errorMessageList = e.getFieldErrors().stream()
                    .map(it->{
                        var format = "%s :{ %s } 은 %s";
                        //                                   어떤 필드에서 어떤 값이 거절당했는지, 디폴트 메세지 출력
                        var message = String.format(format, it.getField(),it.getRejectedValue(),it.getDefaultMessage());
                        return message;
                    }).collect(Collectors.toList());

            var error = Api.Error.builder()
                    .errorMessage(errorMessageList)
                    .build();

            var errorResponse = Api.builder()
                    .resultCode(String.valueOf(HttpStatus.BAD_REQUEST.value()))
                    .resultMessage(HttpStatus.BAD_REQUEST.getReasonPhrase())
                    .error(error)
                    .build();
            return ResponseEntity
                    .status(HttpStatus.BAD_REQUEST)
                    .body(errorResponse);
        }

}

controller 부분에는 정상 로직만 남겨두어 간결해진다.

@Slf4j
@RestController
@RequestMapping("/api/user")
public class UserApiControllerValidate {
    @PostMapping("")
    public Api<UserRegisterRequest> register(
            @Valid
            @RequestBody
            Api<UserRegisterRequest> userRegisterRequest
    ){
        log.info("init : {}",userRegisterRequest);

        var body = userRegisterRequest.getData();
        Api<UserRegisterRequest> response =  Api.<UserRegisterRequest>builder()
                .resultCode(String.valueOf(HttpStatus.OK.value()))
                .resultMessage(HttpStatus.OK.getReasonPhrase())
                .data(body)
                .build();
        return response;
    }
}
profile
하루하루 차근차근🌱

0개의 댓글