Validation이란?
로직을 처리하기 위해 필요한 데이터 ( 사용자 또는 다른 서버의 request 등 )의 값이 유효한지,
잘못된 데이터인지 확인하는 단계를 뜻합니다.
예를들어 이메일 데이터를 받을 때, 이메일의 형식이 일치하지 않는다면, 처리를 하지 못하기에
사전에 확인하고 검증합니다.
Bean Validation
Spring에서는 validation을 위해 Bean Validation 라이브러리를 제공합니다.
Bean Validation은 유효성 검증에 대한 여러 에노테이션을 제공합니다.
@NotNull
|
null 불가
|
@NotEmpty
|
null, “” 불가
|
@NotBlank
|
null, “”. “ “ 불가
|
@Size
|
문자 길이 측정
|
@Max
|
최대값
|
@Min
|
최소값
|
@Positive
|
양수
|
@Negative
|
음수
|
@Email
|
E-mail 형식
|
@Pattern
|
정규 표현식
|
Spring에서 gradle 기준 해당 의존성을 추가해주면 간단하게 사용 가능합니다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
사용법
회원가입을 위해 유저 정보를 request dto 객체를 통해 받고 Validation을 적용하는 예시를 보고 확인해보겠습니다.
@Getter
@Setter
public class SignupRequestDto {
@NotBlank(message = "아이디를 입력해주세요")
private String username;
@Size(min = 5, message = "비밀번호는 5자리 이상이어야 합니다.")
private String password;
@Email(message = "잘못된 이메일 형식입니다.")
private String email;
private boolean admin = false;
private String adminToken = "";
}
위처럼 각 필드에 필요한 어노테이션을 명시 한 후 Controller의 RequestBody에 @Valid 어노테이션을 명시하면 해당 검증 어노테이션에 맞게 검증을 수행합니다.
@PostMapping("/user/signup")
public String signup( @Valid SignupRequestDto request) {
userService.signup(request);
return "redirect:/api/user/login-page";
}
예외처리
검증에 실패했을 때 발생하는 오류에 대해 응답을 보내거나 제어를 하고 싶을때는, Controller에서 BindingResult 객체를 받습니다.
@PostMapping("/user/signup")
public String signup(
@Valid SignupRequestDto request,
BindingResult bindingResult) {
userService.signup(request);
return "redirect:/api/user/login-page";
}
bindingResult.getFieldErrors() 를 통해 필드 에러 리스트를 받고, 해당 리스트를 for each로 돌면서
출력을 해주거나, 원하는 응답의 포맷을 만들어 전달해줄 수 있습니다.
// Validation 예외처리
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
if(fieldErrors.size() > 0) {
for (FieldError fieldError : bindingResult.getFieldErrors()) {
log.error(fieldError.getField() + " 필드 : " + fieldError.getDefaultMessage());
}
Spring Validator 인터페이스
Spring에서 유효성을 검증하는 다른 방법이 하나 더 있습니다.
바로 Validator 인터페이스를 구현하는 구현체를 작성하고 이를 스프링 빈으로 등록하는 것입니다.
이 방법을 사용하면 위에 Bean Validation에 비해서 조금 더 복잡한 로직을 갖는 유효성 검증이 가능합니다.
다만, Validation을 수행하는 클래스를 추가로 작성해야하므로 코드를 찾기 어렵고, 유지보수가 힘들다는 단점이 있습니다.
사용법
@Component
public class PersonValidator implements Validator {
public boolean supports(Class clazz) { // Validator를 동작시킬 조건
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) { // 조건이 맞을 때 동작하게 될 Validation의 내용
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
}
위에 예시로 든 코드는, Person이라는 Class를 대상으로 나이에 대해 검증을 하는 validator입니다.
supports 메서드는 이 validator가 동작할 타겟을 정의하며,
validate 메서드에서 원하는 검증로직을 작성하면 됩니다.
*validate 메서드말고도 다양한 메서드를 지원하니 확인하면 좋을 것 같습니다!
해당 클래스를 작성하고 사용하는 방법은 다음과 같습니다.
@RestController
@Slf4j
@RequiredArgsConstructor
public class ValidateTestController {
private final PersonValidator personValidator;
/**
* 컨트롤러 호출될 때마다 이 메소드 호출
*/
@InitBinder
public void init(WebDataBinder webDataBinder) {
webDataBinder.addValidators(testValidator);
}
@GetMapping("/validate")
public Object validateTest(@ModelAttribute Person person, BindingResult bindingResult) {
personValidator.validate(person, bindingResult);
if(bindingResult.hasErrors()) {
return bindingResult.getFieldErrors();
}
return "success";
}
}
'프로그래밍 > Spring' 카테고리의 다른 글
[Spring] ObjectMapper - LocalDateTime 직렬화 문제 (0) | 2023.11.17 |
---|---|
[Spring] 스프링(Spring)이란? (2) | 2023.11.14 |
[Spring] REST API 테스트 코드 작성하기 (0) | 2023.11.06 |
[Spring] 테스트 코드에서 JPA metamodel must not be empty! 예외가 발생할 때 (0) | 2023.11.04 |
[Spring] spring-data-jpa Auditing 사용하기 (2) | 2023.11.01 |