스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 섹션5. 검증2 - Bean Validation
앞에서 했었지만 사실 저런 문제들은 이미 수 많은 개발자들이 겪은 문제라서, 더 쉽게 할 순 없을지 고민 끝에 스프링에서 Bean Validation으로써 간단하게 할 수 있도록 지원한다.
public class Item {
private Long id;
@NotBlank
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000)
private Integer price;
@NotNull
@Max(9999)
private Integer quantity;
//...
}
(@NotNull 같은 경우는 갓갓 kotlin에서 기본 지원 타입이다.)
거기다 저렇게 타입 제한 등이 있으면 db에서도 연동해서 쓰기 훨씬 쉽다.
구현체는 validation에 있고, 실제 구현은 hibernate로 한다고 한다.
기본 메세지도 나름 잘 나오는데, 기본값임.
이제 내꺼에 적용해보면
앞에서 직접 Validator 구현체 가져와서 정의하고 했던 것들과 똑같이 작동한다. 물론 앞에 @Validated가 붙어 있어야 함.
어떻게 되냐면 앞에서 직접 구현한 Validator 역할을 글로벌하게 돌면서 하는 스프링의 LocalValidatorFactoryBean이 있기 때문이다. 앞에 @Valid, @Validated같은게 붙으면 얘가 와서 검증해주는데, 검증 오류가 발생하면 FieldError, ObjectError를 생성해서 BindingResult에 담는것까지 알아서 해준다. 주의할 점은 이미 커스텀하게 정의한 게 있다면 검증기가 동작하지 않는다.
적용 순서는 @ModelAttribute에서 타입 변환을 시도해보고 되었을 때 검증을 시도하는 것. 만약 안되었다면 위에서 말했듯 에러로 만들어서 BindingResult에 담는거고.
또 개꿀기능이 있는데, 전에 new addError로 뒤에 단어 나열하는 대신 그냥 rejectValue를 쓰면 MessageCodesResolver가 알아서 메세지 만들어 에러 종류 나열하여 스프링 설정에서 에러 메세지만 적어주면 되었던 것 처럼, 이것도 코드를 나열해준다.
다른 필드와 복합적으로 제약이 있을땐느 @ScriptAssert같은것도 있지만 제약이 심해서 구식이라도 더 좋을 수 있다.
추가와 수정같은 같은 도메인에 대해 다르게 적용할 때 빈 껍떼기 인터페이스 만들어놓고 그룹으로 할 수도 있다. 근데 실무에선 복잡해서 잘 안쓰고 따로 폼을 만들어서 사용한다.
실제로는 상품 추가할 때과 수정할 때 폼이 다른 경우가 대부분이라, 생성용 폼, 수정용 폼 따로 만든다.
폼데이터 말고 json같은 api로 만들 때. json 형식이니 @ModelAttribute는 안사용한다.
로그를 보면 에러가 떴을 경우 객체의 타입 같은게 다르면 앞의 경우들과는 다르게 컨트롤러에 들어가지도 않고 바로 에러가 터진다. 이유는 @ModelAttribute는 각 필드마다 값을 하나하나 넣어줬는데 얘는 json이 객체로 변환이 되야 뭘 하든 말든 한다. 그래서 하나가 잘못되면 한번에 다 에러가 뜬다. 타입이 아닌 다르게 해서 에러가 뜬 경우는 BindingResult의 getAll로 해줘서 배열 형태로 반환한 것. 정상적인 경우는 스프링이 기본값으로 만든 json 응답.