2023-07-24-TIL
2023-07-24-TIL
Today I Learned
Validation
Spring Boot에서 요청 값을 검증하는 표준 방법은 Bean Validation(JSR 380) 애너테이션이다. 필드에 @NotNull, @Size, @Email 같은 제약을 선언하고, 컨트롤러 파라미터에 @Valid를 붙이면 Spring이 구현체인 Hibernate Validator로 검증을 실행한다. Baeldung 글에 따르면 Spring Boot 2.3부터는 spring-boot-starter-validation 의존성을 따로 추가해야 한다.
검증 실패를 처리하는 방식은 두 가지다.
@RequestBody에@Valid를 붙인 경우: 실패하면MethodArgumentNotValidException이 던져진다.@ExceptionHandler나@RestControllerAdvice에서getBindingResult()로 필드별 오류를 꺼내 응답을 만든다.- 폼 바인딩인 경우: Spring 가이드처럼
@Valid파라미터 바로 뒤에BindingResult를 두면 예외 대신 오류가BindingResult에 담기고, 컨트롤러가 직접 분기한다.
Spring Framework 3.2 레퍼런스의 Validation 장은 오래된 버전이지만 Validator 인터페이스와 데이터 바인딩이 어떤 관계인지 설명하는 부분은 지금도 참고할 만하다.
- https://cjw-awdsd.tistory.com/50
- https://devfunny.tistory.com/866
- https://www.baeldung.com/spring-boot-bean-validation
- https://reflectoring.io/bean-validation-with-spring-boot/
- https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/validation.html
- https://velog.io/@_koiil/SpringBoot-Spring-Validation%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%A6%9D
- https://spring.io/guides/gs/validating-form-input/
- https://devfunny.tistory.com/866
- https://tychejin.tistory.com/368
Validation for LocalDateTime
이 Stack Overflow 질문은 JSON 본문의 "2020-08-20T12:30:18+0000"을 LocalDateTime 필드로 받으려다 400 응답을 받는 상황이다. 필드에는 @NotNull과 @DateTimeFormat이 붙어 있었다.
여기서 구분할 점은 날짜 형식 문제가 Bean Validation 단계까지 가지 않는다는 것이다. @RequestBody는 Jackson이 먼저 역직렬화하고, 형식이 맞지 않으면 그 단계에서 실패해 @NotNull 같은 제약은 실행되지도 않는다. @DateTimeFormat은 요청 파라미터나 폼 바인딩에 쓰이는 Spring 쪽 설정이라 JSON 본문에는 적용되지 않는다. 답변은 Jackson의 커스텀 StdDeserializer를 만들어 @JsonDeserialize로 지정하는 방법을 제시한다. 또 LocalDateTime은 오프셋 정보를 담지 않는 타입이라, +0000 같은 오프셋이 의미가 있다면 OffsetDateTime이 더 맞는 타입이다.
- https://stackoverflow.com/questions/63507303/spring-boot-bean-validation-for-locatdatetime
Optimistic Locking in JPA
낙관적 잠금은 충돌이 드물다고 보고 잠금을 걸지 않는 대신, 커밋 시점에 그사이 다른 트랜잭션이 같은 행을 바꿨는지 확인하는 방식이다. Baeldung 글에 정리된 동작은 이렇다.
- 엔티티에
@Version필드를 둔다. 버전 필드가 있는 엔티티는 기본으로 낙관적 잠금이 적용된다. - 수정할 때 읽어 둔 버전 값과 DB의 버전 값을 비교한다. 같으면 갱신하면서 버전을 올리고, 다르면
OptimisticLockException을 던진다. - 예외가 나면 현재 트랜잭션은 롤백 대상으로 표시된다. 그래서 재시도는 새 트랜잭션에서 다시 읽는 것부터 해야 한다.
LockModeType.OPTIMISTIC_FORCE_INCREMENT처럼 엔티티를 바꾸지 않아도 버전을 올리는 잠금 모드도 있다.
- https://www.baeldung.com/jpa-optimistic-locking
REST-Assured
REST Assured는 REST API를 테스트하기 위한 Java DSL이다. README는 Ruby나 Groovy 같은 동적 언어에서 하던 간단한 API 테스트를 Java로 가져오는 것을 목표로 든다. given()에 파라미터와 인증을, when()에 요청을, then()에 응답 검증을 쓰는 구조라 테스트가 시나리오처럼 읽힌다.
1
2
3
given().param("key1", "value1")
.when().post("/somewhere")
.then().statusCode(200).body(containsString("OK"));
응답 JSON은 body("lotto.winners.winnerId", hasItems(23, 54))처럼 경로 표현식과 Hamcrest 매처로 검증한다. 실제 서버를 띄운 인수 테스트에서 주로 쓰고, Spring MockMvc와 연동하는 모듈도 있다.
- https://github.com/rest-assured/rest-assured
- https://loopstudy.tistory.com/427
댓글
아직 댓글이 없습니다