바트심슨으로 하루만 살고 싶다

[스프링 프레임워크]게시판 만들기 #4 : 회원가입 본문

Java/Spring

[스프링 프레임워크]게시판 만들기 #4 : 회원가입

바트심슨바게트 2023. 2. 15. 02:58

* 이전 내용
[스프링 프레임워크]게시판 만들기 #3 : 데이터베이스 테이블 생성 및 게시판 카테고리 출력, 페이지 상하단 고정

 

[스프링 프레임워크]게시판 만들기 #3 : 데이터베이스 테이블 생성 및 게시판 카테고리 출력, 페

* 이전 내용 [스프링 프레임워크]게시판 만들기 #2 : Spring과 오라클 DB 연동 및 데이터 베이스 세팅, dependency 세팅 [스프링 프레임워크]게시판 만들기 #2 : Spring과 오라클 DB 연동 및 데이터 베이스

11027bart.tistory.com


회원가입 

1. 회원가입 제약조건 설정하기

회원정보(이름, 아이디, 비밀번호 )를 입력받고 회원가입 진행하기
기본적인 회원가입 폼은 아래 사진과 같다.

고려해야 할 사항 및 지정할 제약조건

1. 이름은 3자 ~ 5자의 한글로 입력
    아이디, 비밀번호, 비밀번호 확인은 5자 ~ 10자의 영문 대, 소문자와 숫자로 입력
2. 모든 텍스트 입력
3. 데이터 베이스의 id가 존재하는지의 여부 확인
   3 - 1. 중복확인을 하지 않고는 회원가입을 할 수 없도록 하기
4. 비밀번호와 비밀번호 확인의 입력이 같은지 확인하기
5. 모든 조건을 통과하면 회원가입 완료 알림창 띄우기

Join.jsp ( 회원가입 폼 )

hidden으로 idExist를 넣어주었다 - 이것은 중복확인 버튼을 클릭했는지의 여부를 확인할 수 있다.

<form:form action="${root }user/join_pro" method="post" modelAttribute="joinBean">
                  <form:hidden path="idExist"/>
                  <div class="form-group">
                     <form:label path="user_name">이름</form:label>
                     <form:input path="user_name" class="form-control"/>
                     <form:errors path="user_name" style='color:red'/>
                  </div>
                  <div class="form-group">
                     <form:label path="user_id">아이디</form:label>
                     <div class="input-group">
                        <form:input path="user_id" class="form-control" onkeypress="resetIdExist()"/>
                        <div class="input-group-append">
                           <button type="button" class="btn btn-primary" onclick="checkIdExist()">중복확인</button>
                        </div>
                     </div>
                     <form:errors path="user_id" style='color:red'/>
                     
                  </div>
                  <div class="form-group">
                     <form:label path="user_pw">비밀번호</form:label>
                     <form:password path="user_pw"  class="form-control"/>
                     <form:errors path="user_pw" style='color:red'/>
                  </div>
                  <div class="form-group">
                     <form:label path="user_pw2">비밀번호 확인</form:label>
                     <form:password path="user_pw2" class="form-control"/>
                     <form:errors path="user_pw2" style='color:red'/>
                  </div>
                  <div class="form-group">
                     <div class="text-right">
                        <button type="submit" class="btn btn-primary">회원가입</button>
                     </div>
                  </div>
               </form:form>

form 태그를 이용해 회원가입 시 modelAttribute로 지정한 "joinBean"에 해당 데이터들을 가지고 가게 해준다.
회원가입 시 중복확인 버튼 클릭 여부 확인과 비밀번호 일치 확인의 작업을 각각 스크립트에서 onclick과 onkeypress함수를 작성해 설정해줄 수 있다. - 아래에서 설명

User DTO (회원 관련)

2. @Size, @Pattern 어노테이션으로 제약조건 설정하기, 중복확인 버튼 초기화

package co.ky.sol.beans;

public class User {
	
	private int user_idx;
	
	@Size(min=3, max=5)
	@Pattern(regexp="[가-힣]*")
	private String user_name;
	
	@Size(min=5, max=10)
	@Pattern(regexp="[a-zA-Z0-9]*")
	private String user_id;
	
	@Size(min=5, max=10)
	@Pattern(regexp="[a-zA-Z0-9]*")
	private String user_pw;
	
	@Size(min=5, max=10)
	@Pattern(regexp="[a-zA-Z0-9]*")
	private String user_pw2;
	
	private boolean idExist;
	
	//중복확인 = false , 로그인 = false
	//초기값으로 확인을 하지 않은 상태로 만든다.
	public User() {
		this.idExist = false;
	}
    // getter, setter 생략
}

이름(user_name)은 3자 ~ 5자의 한글
아이디, 비밀번호, 비밀번호 확인(user_id, user_pw, user_pw2)은 영문 대, 소문자와 숫자가 포함된 5자 ~ 10자의 조건을
설정했다.


이 상태에서도 에러메세지는 나오지만 엉성한 부분이 있으니 에러메시지를 따로 설정하기 위해 properties를 작성하자.

error.properties 프로퍼티 파일 에러 메시지로 사용하기

Size.joinBean.user_name = 사용자 이름은 3~5글자 사이여야한다.
Pattern.joinBean.user_name = 사용자 이름은 한글로 작성

Size.joinBean.user_id = 사용자 아이디는 5~10 글자 사이여야한다.
Pattern.joinBean.user_id = 사용자 아이디는 영문자 및 숫자로 입력

Size.joinBean.user_pw = 사용자 비밀번호는 5~10 글자 사이여야한다.
Pattern.joinBean.user_pw = 사용자 비밀번호는 영문자 및 숫자로 입력

Size.joinBean.user_pw2 = 사용자 비밀번호는 5~10 글자 사이여야한다.
Pattern.joinBean.user_pw2 = 사용자 비밀번호는 영문자 및 숫자로 입력

NotEquals.joinBean.user_pw = 비밀번호가 일치하지 않습니다.
NotEquals.joinBean.user_pw2 = 비밀번호가 일치하지 않습니다.

CheckyourIdExist.joinBean.user_id = 중복확인을 누른 뒤 회원가입 해주세요

properties를 에러메시지로 대체하기 위해 validate 관련 설정을 해주어야 한다.


3. ServletAppContext에 프로퍼티 파일을 메시지로 사용하기 위한 bean 등록

@Bean
public static PropertySourcesPlaceholderConfigurer PropertySourcesPlaceholderConfigurer() {

	return new PropertySourcesPlaceholderConfigurer();
}

	
@Bean
public ReloadableResourceBundleMessageSource messageSource() {
		
	ReloadableResourceBundleMessageSource res=new ReloadableResourceBundleMessageSource();
	res.setBasenames("/WEB-INF/properties/error");
	return res;
}

PropertySourcesPlaceholderConfigurer
   -  추상 클래스PlaceholderConfigurerSupport를 구현한 클래스
   -  Bean으로 등록해서 사용하며, PropertySource를 여러 개 등록할 수 있다.
   -  PropertySource를 추가하여 @Value 어노테이션의 ${...}${...} 부분에 프로퍼티 값을 주입해 준다.

이전에 DB와 MyBatis 연동시 DBCP에 사용한 db.properties 값 주입

ReloadableResourceBundleMessageSource
   - 
원래 properties로 지정하면 서버가 가동되는 동안에는 값 변경이 불가하지만, 서버를 중지하지 않더라도 properties를 갱신해서 사용 가능
   - 
properties 파일을 등록해 주면 message로 등록 가능


4. Validator 생성하기 - 비밀번호 불일치 확인, 중복확인 버튼 클릭하도록 설정

package co.ky.sol.validator;

public class UserValidator implements Validator {

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

	@Override
	public void validate(Object target, Errors errors) {

		User user = (User) target;
        	//에러가 발생한 객체의 이름을 검사한다.
       	 	//에러 메시지 충돌 방지
		String str = errors.getObjectName();

		//회원가입에 관한 유효성 검사 - 비밀번호 확인
		if (str.equals("joinBean")) {
			if (user.getUser_pw().equals(user.getUser_pw2()) == false) {
				errors.rejectValue("user_pw", "NotEquals");
				errors.rejectValue("user_pw2", "NotEquals");
			}
			// 중복확인을 안했다면 에러 메시지 출력
			if (user.isIdExist() == false) {
				errors.rejectValue("user_id", "CheckyourIdExist");
			}
		}
	}
}

5. Controller에 @InitBinder 선언하기

UserController에 추가한 @InitBinder

@InitBinder : UserValidator 사용 시 @Valid 어노테이션으로 검증이 필요한 객체를 가져오기 전에 수행할 메서드를 지정해 주는 어노테이션

WebDataBinder
- 커맨드 객체를 바인딩하는 객체
- addValidator() 메서드를 통해 UserValidator 객체를 add 해준다는 의미로 데이터 검증을 하겠다는 의미
- @InitBinder 어노테이션이 붙은 메서드를 통해 최초에 호출하여 데이터를 검증

회원 가입 폼에서 해당 오류가 출력되는 것을 확인할 수 있다.


중복 확인 클릭 확인

function checkIdExist() {
  var user_id = $("#user_id").val();

  if (user_id.length == 0) {
    alert("아이디를 입력해주세요");
    return;
  }

  $.ajax({
    url: "${root}user/checkIdExist/" + user_id,
    type: "get",
    dataType: "text",
    success: function (result) {
      if (result.trim() == "true") {
        alert("사용할 수 있는 아이디입니다");
        $("#idExist").val("true");
      } else {
        alert("사용할 수 없는 아이디입니다");
        $("#idExist").val("false");
      }
    },
  });
}

function resetIdExist() {
  $("#idExist").val("false");
}

checkIdExist

  • 중복확인 버튼 클릭 시 입력되어 있는 텍스트가 없다면 다시 입력
  • ajax를 이용해 user_id에 입력된 정보를 매핑 과정을 거쳐 반환된 데이터가 
    true라면 중복확인 버튼은 $("#idExist"). val("true")로 클릭이 진행된 상태로 만들고
    false라면 중복 확인 버튼은 $("#idExist"). val("false")로 클릭이 진행되지 않은 상태로 만든다.

ajax 진행 과정에서 RestController를 이용한다.
url에 user_id를 담아 RestController에서 해당 url을 매핑해 같이 넘어온 파라미터를 checkIdExist 메서드를 이용해
true / false를 반환받아온다.

package co.ky.sol.controller;

@RestController
public class ResController {
	//Json 형태로 객체 데이터를 반환하는 것
	//특정 URL에 접속 시 데이터를 String 형태로 반환해줌
	//데이터를 제공하는 REST API 개발할 때 사용
	//응답 결과가 데이터 (문자열인 경우) 주로 사용

	@Autowired
	private UserService userService;
	
	@GetMapping("/user/checkIdExist/{user_id}")
	public String checkIdExist(@PathVariable String user_id) {
		
		//id가 있다면 
		boolean b = userService.checkIdExist(user_id);
		return b + "";
	}
}

resetIdExist

  • onkeypress로 지정해 해당 인풋에 키 입력이 발생한 경우 $("#idExist").val("false")로 클릭이 진행되지 않은 상태로 만든다.

이제 로그인 폼에서 가지고 오는 데이터를 ModelAttribute를 통해 이름을 지정해 주어야 한다.
( 여러 번 사용되기 때문에 타입이 아닌 이름으로 분류해 주어야 오류가 나지 않는다. )

( UserController 회원가입 매핑)

@GetMapping("/join")
public String join(@ModelAttribute("joinBean") User joinBean) {
	return "user/join";
}
	
@PostMapping("/join_pro")
public String join_pro(@Valid @ModelAttribute("joinBean") User joinBean , 
			                BindingResult result) {

	if(result.hasErrors()) {
		return "user/join";
	}
	//내가 회원가입 폼에 입력한 사용자 정보를 
    //Mapper > DAO > Service를 거쳐 Mapping에서 joinBean에 저장하겠다.
	userService.addUser(joinBean);
		
	return "user/join_success";
}

UserMapper인터페이스 - 회원가입 완료 시 insert문으로 회원정보를 테이블에 삽입하도록 정의

package co.ky.sol.mapper;

public interface UserMapper {
	//중복확인을 위해 user_id를 기준으로 user_name이 존재하는지 확인하는 쿼리문
	@Select("select user_name from user_info_table where user_id=#{user_id}")
	String checkIdExist(String user_id);

	//데이터베이스에 집어넣는 작업이기 때문에 반환형이 없다.
	@Insert("insert into user_info_table(user_idx, user_name, user_id, user_pw) values(user_seq.nextval, #{user_name}, #{user_id}, #{user_pw})")
	void addUser(User joinBean);

}

#{}
파라미터가 String 형태로 들어와 자동적으로 '파라미터' 형태가 된다.
위의 코드에서 #{user_id}는 user_id의 값이 abc라면 쿼리문에는 USER_ID='abc'의 형태가 된다.

@Insert에서 user_seq.nextval은 user_seq 시퀀스를 실행하여 user_idx의 수를 증가시킨다는 의미이다.

create sequence user_seq
start with 0
INCREMENT by 1
MINVALUE 0;

UserDao - 회원 정보와 관련된 정보 주입, 전송 및 DB와 연동되는 클래스

package co.ky.sol.dao;

@Repository
public class UserDao {

	@Autowired
	private UserMapper userMapper;
	//중복 확인
	public String checkIdExist(String user_id) {
		return userMapper.checkIdExist(user_id);
	}
	//회원가입시 정보 삽입
	public void addUser(User joinBean) {
		userMapper.addUser(joinBean);
	}
	
}

UserService - 비즈니스 로직을 처리하는 클래스(DAO에서 정의한 메서드 호출 후 사용)

package co.ky.sol.service;

@Service
public class UserService {

	@Autowired
	private UserDao userDao;
	
	public boolean checkIdExist(String user_id) {
		
		String user_name = userDao.checkIdExist(user_id);
		// name이 없다는 것 = 회원 정보에 이름이 없다.
		if(user_name == null) {
			return true;
		}
		// name이 이미 회원 정보에 존재한다.
		else {
			return false;
		}
	}
	
	public void addUser(User joinUser) {
		//dao에 있는 addUser메서드를 호출
		userDao.addUser(joinUser);
	}
}

checkIdExist(String user_id) 

DB에서 user_id와 일치하는 user_name이 없다면 회원가입 폼에서 
중복 확인 시 사용 가능한 아이디이기 때문에 반환은 true로 주었다.

addUser(User joinUser)

회원가입 폼에서 넘어온 데이터를 DB에 삽입할 수 있다.
(Controller에서 매핑 과정에서 사용됨)


UserController

  • 로그인과 회원가입에 대한 매핑
  • @valid 유효성 검사
  • modelAttribute로 지정한 이름으로 파라미터 데이터를 DTO객체에 지정해 넣는다.
  • BindingResult로 에러가 발생하는지 여부 확인
  • @initBinder로 추가적인 validator 실행
  • UserService를 사용할 수 있도록 @Autowired로 자동주입
  • join_pro에서 service를 이용해 호출
package co.ky.sol.controller;

@Controller
@RequestMapping("/user")
public class UserController {
	
	@Autowired
	private UserService userService;
	
    //회원가입 페이지 요청시 User객체 joinBean을 @ModelAttribute에 
    //"joinBean"으로 회원가입 폼에서 지정한 이름과 같도록 지정한다.
    //이 과정을 통해서 회원가입 완료를 하는 과정에서 해당 입력 데이터들이
    // "joinBean"에 담겨진다.
	@GetMapping("/join")
	public String join(@ModelAttribute("joinBean") User joinBean) {
		return "user/join";
	}
	
    //회원가입 시 에러사항이 발생하지는 않았는지
    //만약 발생하지 않았다면 DB에 회원추가를 진행한다.
	@PostMapping("/join_pro")
	public String join_pro(@Valid @ModelAttribute("joinBean") User joinBean , 
			                BindingResult result) {
		
		if(result.hasErrors()) {
			return "user/join";
		}
		
		userService.addUser(joinBean);
		
		return "user/join_success";
		
	}
}

이제 회원 가입이 제대로 작동하는지 확인해 보자.

회원 가입 시 조건을 만족하지 못하는 경우


중복 확인 클릭시 DB와 겹치는 id가 아닌 경우
중복 확인 클릭시 DB의 저장된 id가 존재하는 경우


회원가입 성공 시
회원가입 성공시 매핑되는 join_success.jsp


user_info_table에 추가된 회원 정보

Comments