본문 바로가기

Server Programming/Spring Boot Full-Stack Programming

[스프링 풀스택 클론 코딩 - 회원가입] (1-5) 회원가입 폼 서브밋 검증

반응형

 

회원가입시 중복 닉네임, 중복 아이디인지 검증하고,

 

해당하는 조건에 충족한지 검증한다.

 

또한, 프론트엔드에서 한번 검증하고, 혹시모를 경우를 대비해 백엔드에서 검증하는 절차를 거친다.


 

AccountController

package com.demo.account;


import javax.validation.Valid;

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 lombok.RequiredArgsConstructor;

@Controller
@RequiredArgsConstructor
public class AccountController {

	private final SignUpFormValidator signUpFormValidator;
	
	@InitBinder ("signUpForm")
	public void initBinder(WebDataBinder webDataBinder) {
		webDataBinder.addValidators(signUpFormValidator);
	}
	
	// sign-up 페이지에 연결된다면
	@GetMapping("/sign-up")
	public String signUpForm(Model model) {
		// model.addAttribute(new SignUpForm()); 생략 가능
		model.addAttribute("signUpForm", new SignUpForm());
		return "account/sign-up";
	}
	// 스프링부트 자동설정에 의해
	// templates에 존재하는 view인 account/sign-up을 리턴한다.

	@PostMapping("/sign-up") // 복합객체는 본디 ModelAttribute로 받지만, 생략가능
	public String signUpSubmit(@Valid @ModelAttribute SignUpForm signUpForm, Errors errors) {
		if (errors.hasErrors()) {
			return "account/sign-up";
		}
		// SignUpForm 도메인에 Valid를 위한 처리 필요
		
//		@InitBinder를 이용해 대체 
//		signUpFormValidator.validate(signUpForm, errors);
//		if (errors.hasErrors()) {
//			return "account/sign-up";
//		}
		// -> 자동으로 SignUpForm 검증을 한다.
		
		// TODO 회원 가입 처리 valid에 안걸리면 회원가입
		return "redirect:/";

	}

}

 

SignUpFormValidate

package com.demo.account;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

import lombok.RequiredArgsConstructor;
 
//의존성 주입을 autowired 사용하지않고, bean과 RequiredArgsConstructor을 이용 
//bean 어노테이션 
@Component
//롬복을 이용해  private final만 생성자로 자동생성 -> 선택가능하므로 사용 
@RequiredArgsConstructor
//public SignUpFormValidator(AccountRepository accountrepository) {
//	this.accountrepository = accountrepository;
//}

public class SignUpFormValidator implements Validator{

	//회원정보를 저장해 중복을 검사하는 변수
	private final AccountRepository accountRepository;
	//ctrl + shift + Y 소문자로 변환, ctrl+n 해당 이름으로 클래스생성
	
	@Override
	public boolean supports(Class<?> aClass) {
		// TODO Auto-generated method stub
		return aClass.isAssignableFrom(SignUpForm.class);
		//SignUpForm 타입의 인스턴스를 검사
	}

	@Override
	public void validate(Object o, Errors errors) {
		// TODO email, nickname -> accountrepository에서 조회
		SignUpForm signUpForm =(SignUpForm)  o;
		if (accountRepository.existsByEmail(signUpForm.getEmail())) {
			errors.rejectValue("email", "invaild.email", new Object[] {signUpForm.getEmail()}, "이미 사용중인 이메일입니다. ");
		}
		//bean을 주입받아야 하므로, bean끼리만 가능
		
	
		if (accountRepository.existsByNickname(signUpForm.getNickname())) {
			errors.rejectValue("nickname", "invaild.nickname", new Object[] {signUpForm.getNickname()}, "이미 사용중인 닉네임입니다. ");
			}
	}
	//실제 DB에서 조회해 중복여부를 파악
}

 

Account Repository

package com.demo.account;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;

import com.demo.domain.Account;

//해당 클래스를 인터페이스로 만든다. -> Account에서, ID타입으로 조회
//기본적으로 write를 안쓰고 읽기만 하게해서 메모리 사용량을 최적화
@Transactional(readOnly = true)
public interface AccountRepository extends JpaRepository<Account, Long> {

	boolean existsByEmail(String email);

	boolean existsByNickname(String nickname);

}

 

SignUpForm

package com.demo.account;


import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.Length;

import lombok.Data;

@Data
public class SignUpForm {

	//프론트엔드에서 검사를 하지만, 사용자가 어떤 방법으로 통과를 할경우를 대비해서 백엔드에서도 검사를 수행한다.
	
	
	// 비어있지 않아야, 길이 설정, 정규식을 통해 패턴정의
	@NotBlank
	@Length(min = 3, max = 20)
	@Pattern(regexp = "^[ㄱ-ㅎ가-힣a-z0-9_-]{3,20}$")
	private String nickname;

	@Email
	@NotBlank
	private String email;

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

}
반응형