[Spring boot 8일차] 회원가입 구현

이경영·2022년 10월 31일
0

스프링부트

목록 보기
9/12
post-thumbnail
post-custom-banner

쿼리

CREATE TABLE T_MEMBER ( MEMBER_SEQ INT NOT NULL AUTO_INCREMENT COMMENT '회원 번호', ACCOUNT VARCHAR(50) NOT NULL COMMENT '계정', PASSWORD VARCHAR(100) NOT NULL COMMENT '비밀번호', NICKNAME VARCHAR(10) NOT NULL COMMENT '닉네임', JOIN_DATE DATETIME NOT NULL COMMENT '가입일자', PRIMARY KEY (MEMBER_SEQ) ) COMMENT='회원' COLLATE='utf8mb4_general_ci' ;

Member.java
회원 도메인 생성

package com.example.domain;

import lombok.Data;

@Data
public class Member {
	
	private int memberSeq;
	private String account;
	private String password;
	private String	nickname;
	private String	joinDate;

}

MemberJoinForm.java : validation을 따로 구현하기 위해
메세지 프로퍼티 추가

package com.example.controller.form;

import javax.validation.GroupSequence;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.Length;

import com.example.validation.ValidationSteps;

import lombok.Data;

@Data
@GroupSequence({
	MemberJoinForm.class,
	ValidationSteps.Step1.class,
	ValidationSteps.Step2.class,
	ValidationSteps.Step3.class,
	ValidationSteps.Step4.class,
	ValidationSteps.Step5.class,
	ValidationSteps.Step6.class,
})
public class MemberJoinForm {
	
	@NotEmpty(groups = ValidationSteps.Step1.class, message = "{MemberSaveForm.account.notEmpty}")
	@Email(groups = ValidationSteps.Step2.class, message = "{MemberSaveForm.account.pattern}")
	private String account;

	@NotEmpty(groups = ValidationSteps.Step3.class, message = "{MemberSaveForm.password.notEmpty}")
	@Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$@$!%*#?&])[A-Za-z\\d$@$!%*#?&]{8,12}$",groups = ValidationSteps.Step4.class, message = "{MemberSaveForm.password.pattern}")
	private String password;
	
	@NotEmpty(groups = ValidationSteps.Step5.class, message = "{MemberSaveForm.nickname.notEmpty}")
	@Length(groups = ValidationSteps.Step6.class, min = 2, max = 10, message = "{MemberSaveForm.nickname.length}")
	private String nickname;


}

config/messages/message.properties

BoardSaveForm.boardType.notEmpty=종류를 선택하세요.
BoardSaveForm.title.notEmpty=제목을 입력해주세요.
BoardSaveForm.contents.notEmpty=내용을 입력해주세요.
BoardSaveForm.userName.notEmpty=회원이름을 입력해주세요.
BoardSaveForm.title.length=제목을 2이상 10이하로 설정해주세요.


MemberJoinForm.account.notEmpty=계정을 입력해주세요
MemberJoinForm.account.email=계정은 이메일 형식으로 임력하세야 합니다.
MemberJoinForm.password.notEmpty=패스워드를 입력해주세요
MemberJoinForm.password.pattern=비밀번호는 영문+숫자+특수문자 혼합 최소8자~12자까지 입력하셔야 합니다.
MemberJoinForm.nickname.notEmpty=닉네임을 입력하세요
MemberJoinForm.nickname.length=닉네임은 최소 2자~최대 10자까지 입력하셔야 합니다.
  • Memeber.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.mapper.MemberMapper">

	<!-- 계정이 있는지 없는지 -->
  	<select id="selectMemberAccount" parameterType="String">
  		SELECT COUNT(1)
  		FROM T_MEMBER
  		WHERE ACCOUNT = #{account}
  	</select>
  	
  	<insert id="insertMember" 
  		parameterType="com.example.domain.Member">
  		INSERT INTO T_MEMBER
  		(
  			ACCOUNT,
  			PASSWORD,
  			NICKNAME,
  			JOIN_DATE
  		)
  		VALUES
  		(
  			#{account},
  			#{password},
  			#{nickname},
  			NOW()
  		)
  	</insert>
	
</mapper>

MemberMapper.java

package com.example.mapper;

import com.example.controller.form.MemberJoinForm;

public interface MemberMapper {
	
	int selectMemberAccount(String account);
	
	void insertMember(MemberJoinForm form);
	

}
  • MemberService.java
package com.example.service;

import org.springframework.stereotype.Service;

import com.example.controller.form.MemberJoinForm;
import com.example.mapper.MemberMapper;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class MemberService {
	
	private final MemberMapper memberMapper;
	
	public int selectMemberAccount(String account) {
		return memberMapper.selectMemberAccount(account);
	}
	
	public void insertMember(MemberJoinForm form) {
		memberMapper.insertMember(form);
	}
	

}
  • MemberController.java
package com.example.controller;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.controller.form.MemberJoinForm;
import com.example.service.MemberService;

import lombok.RequiredArgsConstructor;

@Controller
@RequestMapping("/member")
@RequiredArgsConstructor
public class MemberController {
	
	private final MemberService memberService;
	
	@GetMapping("/form")
	public String form() {
		return "/member/form";
	}
	
	@PostMapping("/join")
	@ResponseBody
	public HttpEntity<Boolean> join(@Validated MemberJoinForm form) {
		// 계정 중복체크 : true면 사용중인 계정
		boolean isUseAccount=memberService.selectMemberAccount(form.getAccount()) > 0 ;
		Assert.state(!isUseAccount, "이미 사용중인 계정입니다");
		memberService.insertMember(form);
		
		return new ResponseEntity<Boolean>(true, HttpStatus.OK);
	}
	
	
	/**
	 * 가입 완료 화면
	 * @return
	 */
	@GetMapping("/join-complete")
	public String joinComplete() {
		return "/member/join-complete";
	}

}

HttpEntity와 ResponseEntity의 차이?

  • ResponseEntity : 사용자의 HttpRequest에 대한 응답데이터를 포함하는 클래스, HttpStatus, HttpHeaders, HttpBody를 포함한다. HttpEntity를 상속받으며, RestTemplate 및 @Controller메서드에 사용하고 있다.
  • HttpEntity : HTTP요청 또는 응답에 해당하는 HttpHeader와 HttpBody를 포함하는 클래스.
    HttpEntity 클래스를 상속받아 구현한 클래스가 RequestEntity, ResponseEntity 클래스이다.

member/form.html 파일 생성

<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
  </head>
  <body>
	<div class="container">
		<form id="member-join-form" method="post">
			<input type="hidden" th:name="${_csrf.parameterName}" 
				 th:value="${_csrf.token}" />
			<div class="row mb-3">
				<label for="account" class="col-sm-2 col-form-label">계정</label>
				<div class="col-sm-10">
					<input type="text" class="form-control" 
						name="account" id="account"/>
				</div>
			</div>
			<div class="row mb-3">
				<label for="password" class="col-sm-2 col-form-label">비밀번호</label>
				<div class="col-sm-10">
					<input type="password" class="form-control" 
						name="password" id="password" />
				</div>
			</div>
			<div class="row mb-3">
				<label for="nickname" class="col-sm-2 col-form-label">닉네임</label>
				<div class="col-sm-10">
					<input type="text" class="form-control" 
						name="nickname" id="nickname"/>
				</div>
			</div>
				<div class="row mb-3">
				<label for="nickname" class="col-sm-2 col-form-label">파일업로드</label>
				<div class="col-sm-10">
					<input type="file" class="form-control" 
						name="profileImage" id="profileImage"/>
				</div>
			</div>
			<button type="submit" class="btn btn-primary">저장</button>
		</form>
	</div>
	<!-- 비동기로 넘기기 위한 준비  -->
	<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
	<script>
	$(function(){
		var $form= $('#member-join-form'); //html의 element 찾음 
		$form.submit(function() {
			try{
/* 			var data = {
				account: $form.find('input[name=account]').val(),	
				password: $form.find('input[name=password]').val(),	
				nickname: $form.find('input[name=nickname]').val(),	
				
			} */
			var formData=new FormData($form[0])
			console.log('formData',formData);
			
		
		//서버 전송하기전에 Object형태를 String으로 바꿔줘야함
		
/* 		var jsonValue=JSON.stringify(data);
		
		console.log('jsonValue',jsonValue) */
		
		//form에서 submit이 발생하는 것은 핸들링.
		
			//비동기로 전송하기 위해
			$.ajax({
				url: '/member/join',
				type: 'post',
				data: formData,
				contentType:false,
				processData:false,
				success: function() { //서버로 따지면 컨트롤러
					location.href='/member/join-complete';
				},
				error: function(data){
					//console.log(data);
					console.log(data.responseJSON);
					alert(data.responseJSON.message);
				}
				
			});
			}catch(e){
				console.log(e);
			}
			//페이지가 전환되지 않게 방지
			return false;
		});
	});
	</script>
  </body>
</html>

비동기 업로드를 하기 위해 ajax와 FormData를 이용한 업로드:
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=mk1126sj&logNo=221016837263

profile
꾸준히
post-custom-banner

0개의 댓글