출처 : www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-JPA-%EC%9B%B9%EC%95%B1/dashboard
회원가입 폼 검증
- JSR 303 애노테이션 검증
- 값의 길이, 필수값
- 커스텀 검증
- 중복 이메일, 닉네임 여부 확인
- 폼 에러 있을 시, 폼 다시 보여주기
회원 가입 처리
- 회원 정보 저장
- 인증 이메일 발송
- 처리 후 첫 페이지로 리다이렉트 ( Post-Redirect-Get 패턴)
실습
- 시작 커밋 : bc88d9e4d7f892b09146c94260dcf144b05cd1c6
- 완료 커밋:
frontend개발자가 thymeleaf말고 다른것으로 개발한다고 가정 할 경우
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{/login}">로그인</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{/signup}">가입</a>
</li>
ThymeLeaf로만 attribute를 던진다고 가정
<li class="nav-item">
<a class="nav-link" th:href="@{/login}">로그인</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/signup}">가입</a>
</li>
회원가입 폼 검증
- JSR 303 애노테이션 검증
- 값의 길이, 필수값
2009년 자바 servlet2.3 JSR validation을 확장한 annotation validation 및 hibernate활용
- 커스텀 검증
- 중복 이메일, 닉네임 여부 확인
package com.studyolle.account;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
@Component
// bean과 bean들만 의존성 주입 받을 수 있기 때문에 component어노테이션
@RequiredArgsConstructor
// lombok -> private fianl에 해당하는 member variable의 생성자를 만들어줌
public class SignUpFormValidator implements Validator {
private final AccountRepository accountRepository; // bean
/*
@RequiredArgsConstructor ->
롬복이 Annotation으로 만들어 줌 어떤 bean이 생성자가 하나만 있고
그 생성자가 받는 parameter들이 bean으로 등록이 되어있다면
spring 4.2이후 부터는 자동으로 bean을 주입해주기 때문에
autowired나 inject같은 어노테이션을 쓰지않아도 의존성 주입이 된다.
public SignUpFormValidator(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}*/
@Override
public boolean supports(Class<?> aClass) {
return aClass.isAssignableFrom(SignUpForm.class);
}
@Override
public void validate(Object o, Errors errors) {
// TODO email, nickname 중복 여부 검사
SignUpForm signUpForm = (SignUpForm)errors;
if(accountRepository.existsByEmail(signUpForm.getEmail())){
errors.rejectValue("email","invalid.email", new Object[]{signUpForm.getEmail()}, "이미 사용중인 이메일입니다.");
// message 소스는 이번에 다루지 않고 국제화 서비스를 가정하고 메시지 다국화를 다루면서
// 그 때 다룰 예정
if(accountRepository.existsByNickName(signUpForm.getNickname())){
errors.rejectValue("nickname","invalid.nickname", new Object[]{signUpForm.getNickname()}, "이미 사용중인 닉네임입니다.");
}
}
}
}
실제로 DB조회 해서 custom한 validata가 있어야 함
- 폼 에러 있을 시, 폼 다시 보여주기
package com.studyolle.account;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import javax.validation.Valid;
@Controller
@RequiredArgsConstructor
public class AccountController {
private final SignUpFormValidator signUpFormValidator;
@InitBinder("signUpForm")
public void initBinder(WebDataBinder webDataBinder) {
webDataBinder.addValidators(signUpFormValidator);
// signUpForm데이터를 받을 때 타입의 camelCase이름을 따라감
// @Valid SignUpForm signUpForm(mapping)
/*
signUpSubmit에
validate 검증을 한번 더 하는 것을 InitBinder로
signUpSubmit에들어 왔을때 validate 검사를 하고
signUpFormValidator.validate(signUpForm, errors);
if(errors.hasErrors());
return "account/sign-up";
}
*/
}
@GetMapping("/sign-up")
public String signUpForm(Model model) {
model.addAttribute(new SignUpForm()); // 객체 attribute의 이름이 된다.
// camel Case 값 -> "signUpForm"문자열이 들어감
return "account/sign-up";
}
@PostMapping("/sign-up")
public String signUpSubmit(@Valid SignUpForm signUpForm, Errors errors) {
// 복합 객체 ( 여러 값) -> ModelAttribute로 받아오는데 파라미터로 쓰일때 생략이 가능하다.
// Data를 컨버젼하거나 binding할때 발생할 수 있는 에러를 받아주는 타입 -> Erros
if(errors.hasErrors()){
//SignUpForm JSR 303 Annotation에 정의한 값에 걸리면
// Binding Errors errors에 담기고 에러가 있다고 조건문에 걸려서 form으로 돌아감
return "account/sign-up";
}
// TODO 회원 가입 처리
return "redirect:/";
}
}
@transaction readonly = true성능 이점에 대한 관련 글
vladmihalcea.com/spring-read-only-transaction-hibernate-optimization/
'프로젝트 정리 > 스프링과 JPA 기반 웹 애플리케이션 개발' 카테고리의 다른 글
7. 회원 가입 : 리팩토링 및 테스트 (0) | 2021.02.19 |
---|---|
6 - 2 . 회원 가입 폼 서브밋 처리 (0) | 2021.02.17 |
5. 회원가입 뷰 (0) | 2021.02.16 |
4. 회원가입 컨트롤러 (0) | 2021.02.15 |
3. 계정 도메인 (0) | 2021.02.15 |