Spring의 Validator 인터페이스를 이용해서 유효성 검사하기

김건우·2023년 1월 27일
0

spring

목록 보기
3/9
post-thumbnail

Validator 인터페이스

Validator 인터페이스에는 두 가지 메소드가 정의되어있다.

boolean supports(Class<?> clazz) {
    // 인스턴스가 검증 대상 타입인지 확인
}
void validate(Object target, Errors errors) {
    // 실질적인 검증 작업
}

프로젝트에서의 유효성 검사 도입

  • 해당 아래의 코드는 DTO에서의 Valid의 어노테이션의 검증이 끝난 뒤(예를들어 @NotBlank,@Email 같은 형식) 이미 존재하는 email인지 nickName인지 유효성 검사하는 Validator 인터페이스를 overide한 것 이다.
  • 아래의 Validator는 spring의 bean을 주입 받아야하기 때문에 bean으로 만들어줘야한다. -> 따라서 @Component를 붙여주자! 빈과 빈들만 주입을 받을 수 있다.
@Component
@RequiredArgsConstructor
public class SignUpFormValidator implements Validator {

    private AccountRepository accountRepository;

    @Override
    public boolean supports(Class<?> aClass) {
        return aClass.isAssignableFrom(SignUpForm.class);
    }

    @Override
    public void validate(Object object, Errors errors) {
        SignUpForm signUpForm = (SignUpForm) object;
        /**이메일 중복 일 시**/
        if (accountRepository.existsByEmail(signUpForm.getEmail())) {
            errors.rejectValue("email","invalid.email",new Object[]{signUpForm.getEmail()},"이미 사용중인 이메일 입니다.");
        }
        if (accountRepository.existsByNickname(signUpForm.getNickname())) {
            errors.rejectValue("nickname", "invalid.nickname", new Object[]{signUpForm.getEmail()}, "이미 사용중인 닉네임입니다.");
        }
    }
}
  • 위의 Validator에서 사용된 userRepository 메서드 🔽
public interface AccountRepository extends JpaRepository<Account,Long> {

    boolean existsByEmail(String email);
    boolean existsByNickname(String nickname);
}

위의 SignUpFormValidator를 이제 Controller 에서 사용할 것 이다. 그전에 우선 @InitBinder에 대해서 알아보자.

@InitBinder

  • Spring Validator를 사용 시 @Valid 어노테이션으로 검증이 필요한 객체를 가져오기 전에 수행할 method를 지정해주는 어노테이션이다
  • 예를 들어 @InitBinder("특정 객체 이름")으로 지정해주면 "특정 객체"에만 해당 @InitBinder 가 적용된다.
  • 이점 : 해당 valid를 사용할 controller의 코드 길이가 줄고 다른 곳에서도 재사용이 가능하다.

UserController

@Controller
@RequiredArgsConstructor
public class AccountController {

    private final SignUpFormValidator signUpFormValidator;
    private final AccountRepository accountRepository;
    private final ConsoleMailSender mailSender;

    @InitBinder("signUpForm")
    public void initBinder(WebDataBinder webDataBinder) {
        webDataBinder.addValidators(signUpFormValidator);
    }


    @GetMapping("/sign-up")
    public String signUpForm(Model model) {
        model.addAttribute("signUpForm", new SignUpForm());
        return "account/sign-up";
    }

    @PostMapping("/sign-up")
    public String signUpSubmit(@Valid SignUpForm signUpForm, BindingResult result) {
        if (result.hasErrors()) {
            return "account/sign-up";
        }
        Account account = signUpForm.of();
        Account newAccount = accountRepository.save(account);
        //저장 완료 시 이메일 체크에 필요한 토큰 발급
        newAccount.generateEmailCheckToken();

        // TODO 이메일 보내기
        SimpleMailMessage mail = new SimpleMailMessage();
        mail.setSubject("스터디히어, 회원 가입 인증");
        //
        mail.setText("/check-email-token?token=" + newAccount.getEmailCheckToken()
                + "&email=" + newAccount.getEmail());
        //수신 이메일
        mail.setTo(newAccount.getEmail());
        mailSender.send(mail);
        return "redirect:/";
    }

}

위와 같이 @InitBinder("signUpForm")를 사용하면 카멜케이스로 바인딩을 설정해주어서 SignUpForm 객체를 validator에 추가해서 유효성 검사를 할 수 있다.

profile
Live the moment for the moment.

0개의 댓글