spring

SignUpForm에대한 Validator

고줭 2022. 8. 4. 19:39
@Controller
@RequiredArgsConstructor
public class AccountController {

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

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

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

    @PostMapping("/sign-up")
    public String signUpSubmit(@Valid SignUpForm signUpForm, Errors errors) {
        if (errors.hasErrors()) {
            return "account/sign-up";
        }

        Account account = Account.builder()
                .email(signUpForm.getEmail())
                .nickname(signUpForm.getNickname())
                .password(signUpForm.getPassword()) // TODO encoding 해야함
                .studyCreatedByWeb(true)
                .studyEnrollmentResultByWeb(true)
                .studyUpdatedByWeb(true)
                .build();
        Account newAccount = accountRepository.save(account);

        newAccount.generateEmailCheckToken();
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setTo(newAccount.getEmail());
        mailMessage.setSubject("스터디올래, 회원 가입 인증");
        mailMessage.setText("/check-email-token?token="+ newAccount.getEmailCheckToken() +
                "&email=" + newAccount.getEmail());
        javaMailSender.send(mailMessage);

        return "redirect:/";
    }
}

@PostMapping /sign-up으로 form submit 전송에대한 Validate를 실행합니다.
SignUpForm같은 객체로 받을 경우 @ModelAttribute를 사용해야하지만 기본적으로 생략해도 됩니다.
@Valid 어노테이션으로 Validate를 진행합니다.

@Data
public class SignUpForm {

    @NotBlank
    @Length(min = 3, max = 20)
    @Pattern(regexp = "^[ㄱ-ㅎ가-힣a-zA-Z\\d_-]{3,20}$")
    private String nickname;

    @Email
    @NotBlank
    private String email;

    @NotBlank
    @Length(min = 8, max = 50)
    private String password;
}

@Valid 어노테이션시의 로직을 실행할 어노테이션입니다. 각각의 요소는 비어있으면 안되기 때문에 @NotBlank를 사용합니다.
비슷한 어노테이션으로 @NotNull과 @NotEmpty가 있습니다.

@NotNull의 경우 말 그대로 null만 제외하고 @NotEmpty의 경우 null, ""을 제외합니다. 그치만 " "와 같은 띄어쓰기는 허용합니다.
@NotBlank는 null, "", " " 모두 제외시킵니다.
SignUpForm에 들어가는 nickname, email, password 셋 모두 빈칸도 허용할 수 없으므로 @NotBlank를 사용합니다.

@Length의 경우 길이, @Pattern(regexp = "")는 정규식으로 패턴을 정규화하는 것입니다. @Email을 email의 형식인지를 Validate하는 어노테이션입니다.

@Component
@RequiredArgsConstructor
public class SignUpFormValidator implements Validator {

    private final AccountRepository accountRepository;

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

    @Override
    public void validate(Object target, Errors errors) {
        SignUpForm signUpForm = (SignUpForm) target;
        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.getNickname()}, "이미 사용중인 닉네임입니다.");
        }
    }
}

AccountController에 주입된 SignUpFormValidator의 경우 springframework에서 제공하는 Validator객체를 implements해 사용합니다.

supports(Class<?> clazz), validate(Object target, Errors errors)을 Override해서 사용합니다.