지난번에 공부했던 Validator와 @Validated를 이용한 검증 방법은 구현과 사용 과정에서 공통적이고 반복적인 일들이 많았다.
그리고 사실 대부분의 검증 로직은 null 체크, 빈 문자열 체크 등 제한적이고 일반적인 로직이 대부분이다.
java는 어노테이션을 이용한 Bean Validation 기능을 제공하며, 스프링과 통합해서 사용하기 굉장히 편하다.
Bean Validation은 특별한 구현체를 통칭하는 것이 아닌 여러 어노테이션과 인터페이스의 모음을 이야기하며
구현체는 여러 종류가 있는데 주로 Hibernate Validator를 사용한다.(Spring boot 이용시에도 기본으로 제공한다.)
Bean Validation 사용 방법
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CreateUserRequest{
@NotBlank
private String accountId;
@NotBlank
private String password;
@NotBlank
private String name;
}
이렇게 dto 혹은 엔티티에 @NotBlank, @NotNull 등의 어노테이션을 달아주기만 하면 간편하게 사용할 수 있다.
//유저 생성
@PostMapping("/admin/users/create-users")
public String createUser(@Valid CreateUserRequest createUserRequest,
BindingResult bindingResult){
if(bindingResult.hasErrors()){ // 검증 실패
return "admin/users/users-create-form";
}
else { //검증 성공
User user = createUserRequest.toUser();
Long userId = userService.register(user);
return "redirect:/admin/users/read-users";
}
}
컨트롤러에선 ModelAttribute앞에 @Valid 혹은 @Validated 어노테이션을 달아주기만 하면 된다.
Bean Validation의 작동 방식
- springboot-stater-validation 라이브러리를 등록한다.
- 스프링이 LocalValidatorFactoryBean을 글로벌 Validator로 등록한다.
- @Valid, @Validated를 컨트롤러에 달아주면 어노테이션을 기반으로 검증한다.
- 검증 오류시 FieldError, ObjectError 생성해서 BindingResult에 담아준다.
- 검증 순서
- ModelAttribute로 각각 필드에 타입 변환 시도
- 성공하면 다음, 실패하면 “typeMismatch”로 FieldError 추가
- Validator 적용(실패한 필드는 적용 x)
- 어노테이션 따라서 검증
- 에러 코드 출력 방식
- 에러 코드 메세지는 bindingResult.rejectValue(”어노테이션 이름”)과 동일하게 등록된다.
- 어노테이션 이름를 기반으로 MessageCodeResolver가 메세지 코드 배열을 만들어준다.
- @...(message="...") 를 사용하면 defaultMessage를 설정해줄 수 있다.
- 1,2,3이 전부 없으면 라이브러리 제공 기본값 사용해 제공한다.
오브젝트 오류의 경우 @ScriptAssert()를 사용해서 처리할 수 있지만 제약이 많아서 실무에서 잘 사용하지 않는다.
강의에선 그냥 자바 코드를 이용해서 직접 검증한 후 bindingResult에 담는 것을 추천했다.
@Valid와 @Validated의 차이점?
@Valid
- 자바 표준 스펙
- ArgumentResolver를 통해 진행된다.
- 컨트롤러에서만 사용 가능하다
@Validated
- 스프링 프레임워크에서 지원
- AOP기반으로 검증을 지원한다.
- 스프링 빈으로 등록된 모든 클래스에서 활용할 수 있다.
- 유효성 검증 그룹 기능을 지정할 수 있다.
Bean Validation - Http Message Converter
@PostMapping("/users")
public ResponseEntity<Object> registerUser(@Valid @RequestBody CreateUserRequest request,
BindingResult bindingResult){
if(bindingResult.hasErrors()){ // 검증 실패
return ResponseEntity.badRequest().body(bindingResult.getAllErrors());
}
else{ // 검증 성공
User user = request.toUser();
Long userId = userService.register(user);
return ResponseEntity.ok(userId);
}
}
form 형식이 아닌 Request Body로 들어오는 데이터 또한 Bean Validation을 적용할수 있다.
@RequestBody 어노테이션이 붙은 객체 앞에 @Valid 또는 @Validated를 사용해 검증하면 된다.
그러나 object type error 등과 같이 객체 바인딩 과정에서 오류가 발생하면
ModelAttribute와 다르게 컨트롤러 호출이 안된다.
ModelAttribute : 필드 단위로 세밀하게 적용 → 타입 안맞아도 나머지 필드 처리 가능
→ bindingResult 달면 컨트롤러 로직 호출 가능
RequestBody : HttpMessageConverter단계에서 JSON 객체 변경 못하면 나머지 필드 다 호출 불가능
→ 컨트롤러, Validator 다 사용 불가능
'Spring > Spring MVC' 카테고리의 다른 글
사지방에서 Spring 공부하기 Web MVC #10 - 필터와 인터셉터 (0) | 2023.08.27 |
---|---|
사지방에서 Spring 공부하기 Web MVC #9 - 로그인 처리 (쿠키, 세션) (0) | 2023.08.26 |
사지방에서 Spring 공부하기 Web MVC #7 - Validation(검증) (0) | 2023.08.20 |
사지방에서 Spring 공부하기 Web MVC #6 - 메세지 국제화 (5) | 2023.08.19 |
사지방에서 Spring 공부하기 Web MVC #5 - Thymeleaf 와 스프링 통합 (0) | 2023.08.19 |