Spring
[Spring] 애노테이션 기반의 Bean Validation
이덩우
2023. 7. 25. 11:42
지난 포스팅 : https://dong-woo.tistory.com/94
[Spring] 유효성 검증 - Validation
지금까지 만든 웹 애플리케이션은 폼 입력 시 바인딩 오류가 발생하면 400 Bad Request 화면으로 이동했다. 아마 사용자 입장에서 이런 오류 페이지를 만난다면 당황할 것이다. 또한 입력값을 공백
dong-woo.tistory.com
지난 포스팅에서 유효성 검증, Validation 방식에 대해 점진적인 발전을 거치며 살펴봤다.
하지만 코드가 복잡하다.
자바는 Bean Validation이라는 애노테이션 기반의 검증 방식을 지원해 보다 간단한 코드로 검증 로직을 구현할 수 있다.
Bean Validation에 대해 알아보자.
- Bean Validation 이란
- @NotNull, @Max, @Range 처럼 검증 로직을 애노테이션으로 대체할 수 있는 기능이다.
- Validator 클래스를 따로 만들지 않아도 된다. 검증을 원하는 클래스의 필드마다 원하는 애노테이션을 붙이면 된다.
- Bean Validation은 자바 표준 기술이다.
- 검증 애노테이션과 여러 인터페이스의 집합이다.
- 일반적으로 Bean Validation을 사용하는 구현체는 하이버네이트 Validator이다.
- 애노테이션은 필요한 상황마다 레퍼런스를 참고하자!
- FieldError, ObjectError
- 필드에러는 다루기 편한데..
- 오브젝트 에러는 다루기 어렵다.
- 이전과 달리 검증의 대상이 되는 클래스의 필드앞에 애노테이션을 붙이기 때문이다.
- @ScriptAssert 애노테이션을 사용하면 대처할 수 있긴 한데 이 방법도 만능 해결책이 아니다.
- 그래서 오브젝트 에러는 이전처럼 직접 자바코드로 검증 로직을 만드는 것도 괜찮다.
- Bean Validation 한계
- 지금까지는 최초 등록 상황에서 적용해봤다.
- HTML <--> 저장소 안에서 데이터가 움직일 때 모두 동일하게 Item 객체를 사용했다.
- 수정 시 검증 단계를 추가한다고 생각해보자.
- 등록 시 요구되는 폼 데이터와 수정 시 요구되는 폼 데이터의 형식은 보통 다르다.
- 따라서 모두 같은 Item 객체로 HTML부터 저장소까지 데이터를 나를 수 없다.
- 여기서 문제가 생긴다. 하나의 클래스 타입으로 데이터를 운반할 수 없어 Bean Validation을 적용할 수 없는 것이다.
- groups
- 하나의 클래스 타입을 사용하되 구분짓기 위한 인터페이스를 껍데기로 만든다.
- Bean Validation 애노테이션 뒤에 괄호를 붙여, group = SaveCheck.class 와 같이 어떤 상황에서 사용할 것인지 명시해주는 것이다.
- 등록 컨트롤러에 @Validated(SaveCheck.class) 추가
- 수정 컨트롤러에 @Validated(UpdateCheck.class) 추가
- 하지만 groups를 사용하니 전반적으로 복잡도가 올라갔다.
- 실제로 groups 기능은 잘 사용되지는 않는다.
- 실무에서는 주로 다음에 등장하는 폼 객체를 분리하는 방식을 사용하기 때문이다.
- 참고로 자바 표준인 @Valid에는 groups기능이 없다. 따라서 사용하려면 @Validated를 사용해야 한다.
- 등록, 수정 Form 객체 분리
- 등록, 수정 시 요구되는 데이터가 다를 수 있는데, 하나의 클래스 타입을 사용해 데이터를 운반하는 것이 문제였다.
- 아예 원하는 타입으로 객체를 분리해서 사용하고, 필요할 때 Item으로 만들어주면 된다.
- @RequestBody와 @Validated
- HTML 폼을 통해 입력된 데이터를 검증하는 방식에 대해 알아봤다.
- 하지만 데이터를 서버로 전송하는 방식은 HTTP RequestBody에 데이터를 직접 담아서 전송하는 방식도 있다.
- 이런 경우는 검증을 어떻게 할까?
- 마찬가지로 @Validated 애노테이션을 동일한 방식으로 사용할 수 있다.
- 다만 차이점이 있다.
- 기존 폼 데이터를 바인딩 할 때 타입 오류가 발생하면, 해당 필드는 타입미스매치를 스프링이 자동으로 넣어주고 컨트롤러가 호출됐다.
- 하지만 @RequestBody에서 Json타입으로 데이터가 넘어온다면 하나의 객체 단위로 넘어오기 때문에, 필드마다 쪼개서 생각할 수 없다. 따라서 @RequestBody로 Json -> 객체타입 바인딩자체가 실패한다.
- 이런 경우 HttpMessageConverter단계에서 실패한 것이다.
- 예외가 발생하게 되는데, 이 예외를 처리하는 방법은 추후에 알아보겠다.
출처 : 인프런, 김영한의 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술