본문 바로가기

SpringBoot

SpringBoot(21) - 복습 예제(회원가입 기능 구현)

728x90
반응형

1) SpringBoot

   1-1) 복습 예제

      1-1-1) 회원가입 기능 구현

 

 

 

 

 

1) SpringBoot

1-1) 복습 예제

[web5] 안에 build.gradle 파일 내용 아래와 같이 설정

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.3.2'
	id 'io.spring.dependency-management' version '1.1.6'
}

group = 'net.datasa'
version = '0.0.1-SNAPSHOT'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(17)
	}
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	// implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	// implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.mysql:mysql-connector-j'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	// testImplementation 'org.springframework.security:spring-security-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
	useJUnitPlatform()
}

 

 

[src/main/resources] - [templates] 안에 application.properties 파일 내용 아래와 같이 작성

spring.application.name=web5

#접속 포트번호
server.port=8888
#Context Path
server.servlet.context-path=/

#Logback 사용. 전체를 대상으로 로깅 레벨 지정
#error>warn>info>debug>trace
logging.level.root=info
#특정 패키지를 대상으로 로깅 레벨 지정
logging.level.net.datasa.web5=debug

# MySQL 데이터베이스 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Seoul&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

# JPA 설정
# DB 구조와 Entity가 안 맞을 때 에러를 내주는 역할을 하는 것이 바로 및의 "~ddl-auto=validate" 설정이다.
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type.descriptor.sql=trace

spring.jackson.time-zone=Asia/Seoul

 

 

[web5] 안에 web5.txt 파일 생성 후 아래와 같이 내용 정리

새 프로젝트 : web5
기본 패키지 : net.datasa.web5
의존성 추가 : 기본 4개 + JPA + MySQL 드라이버 + spring Security
경로 : http://localhost:8888

패키지
net.datasa.web5.controller
net.datasa.web5.service
net.datasa.web5.domain
net.datasa.web5.domain.entity
net.datasa.web5.domain.dto
net.datasa.web5.repository
net.datasa.web5.security
net.datasa.web5.util

* 각 기능별 경로
/member/joinForm : 가입폼
/member/join : 가입처리
/member/loginForm : 로그인폼
/member/login : 로그인 처리
/member/info : 개인정보 수정
/board/write : 글쓰기
/board/delete : 글삭제
... 생략

 

 

 

 

1-1-1) 회원가입

(1) [src/main/resources] - [templates] 안에 home.html 파일 생성 후 아래와 같이 작성

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://thymeleaf.org"
		xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
	<meta charset="UTF-8">
	<title>web5</title>
</head>
<body>
	<h1>[ web5 ]</h1>
	
	<p>
		<a href="member/joinForm">회원가입</a>
	</p>
	<p>
		<a href="">로그인</a>
	</p>
	<p>
		<a href="">로그아웃</a>
	</p>
	<p>
		<a href="">개인정보 수정</a>
	</p>
	<p>
		<a href="">게시판</a>
	</p>
	
</body>
</html>

 

 

(2) 회원 정보 저장(회원가입)을 위한 DB 구조 설계

-- DB 구조
-- 회원정보(테이블명 : web5_member)

create table web5_member(
--  컬럼명              자료형            제약조건           						설명
	member_id         varchar(30)    primary key,    						-- 회원을 구분하는 아이디  
	member_password   varchar(100)   not null,       						-- 비밀번호(암호화)      
	member_name       varchar(30)    not null,       						-- 회원 이름      
	email             varchar(50),                   						-- 이메일  
	phone             varchar(30),                   						-- 전화번호
	address           varchar(200),                  						-- 주소
	enabled           tinyint(1)     default 1 check(enabled in (0, 1)),   -- 계정상태(1: 사용가능, 0: 사용 불가능)	
	rolename          varchar(30)    default 'ROLE_USER' check(rolename in ('ROLE_USER', 'ROLE_ADMIN'))   -- 사용자 구분('ROLE_USER', 'ROLE_ADMIN' 중 하나)
);

select * from web5_member;

drop table web5_member;

commit;

 

 

(3) [src/main/java] - [net.datasa.web5.domain.entity] 안에 MemberEntity.java 파일 생성 후 아래와 같이 작성

package net.datasa.web5.domain.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 회원정보 Entity
 * - Entity : DB와 직접적으로 연동되는 객체
 * */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="web5_member")
public class MemberEntity {
	@Id
	@Column(name="member_id", length = 30)
	private String memberId;
	
	@Column(name="member_password", nullable = false, length = 100)
	private String memberPassword;
	
	@Column(name="member_name", nullable = false, length = 30)
	private String memberName;
	
	@Column(name="email", length = 50)
	private String email;
	
	@Column(name="phone", length = 30)
	private String phone;
	
	@Column(name="address", length = 200)
	private String address;
	
	@Column(name="enabled", columnDefinition = "tinyint(1) default 1 check(enabled in (1, 0))")
	private Boolean enabled;
	
	@Column(name="rolename", length = 30, columnDefinition = "varchar(30) default 'ROLE_USER' check(rolename in ('ROLE_USER', 'ROLE_ADMIN'))")
	private String rolename;
}

 

 

(4) [src/main/java] - [net.datasa.web5.repository] 안에 MemberRepository.java 파일 생성 후 아래와 같이 작성

package net.datasa.web5.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import net.datasa.web5.domain.entity.MemberEntity;

@Repository
public interface MemberRepository extends JpaRepository<MemberEntity, String> {

}

 

 

(5) [src/main/java] - [net.datasa.web5.domain.dto] 안에 MemberDTO.java 파일 생성 후 아래와 같이 작성

package net.datasa.web5.domain.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 회원정보 DTO
 * */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberDTO {
	String memberId;             // 회원 아이디
	String memberPassword;       // 비밀번호
	String memberName;           // 이름
	String email;                // 이메일
	String phone;                // 전화번호
	String address;              // 주소
	Boolean enabled;             // 계정상태
	String rolename;             // 권한명
}

 

 

(6) [src/main/java] - [net.datasa.web5.service] 안에 MemberService.java 파일 생성 후 아래와 같이 작성

package net.datasa.web5.service;

import org.springframework.stereotype.Service;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import net.datasa.web5.domain.dto.MemberDTO;
import net.datasa.web5.domain.entity.MemberEntity;
import net.datasa.web5.repository.MemberRepository;

/**
 * 회원정보 관련 처리 서비스
 * */

@RequiredArgsConstructor
@Service
@Transactional
public class MemberService {
	private final MemberRepository memberRepository;

	/**
	 * 가입 처리
	 * */
	public void memberJoin(MemberDTO dto) {
		MemberEntity entity = MemberEntity.builder()
				// DTO로 전달받은 값들을 Entity에 세팅
				.memberId(dto.getMemberId())
				.memberPassword(dto.getMemberPassword())
				.memberName(dto.getMemberName())
				.email(dto.getEmail())
				.phone(dto.getPhone())
				.address(dto.getAddress())
				// 기타 추가 데이터를 Entity에 세팅
				.enabled(true)
				.rolename("ROLE_USER")
				.build();
		
		// DB에 저장
		memberRepository.save(entity);
		
	}

}

 

 

(7) [src/main/java] - [net.datasa.web5.controller] 안에 MemberController.java 파일 생성 후 아래와 같이 작성

package net.datasa.web5.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.datasa.web5.domain.dto.MemberDTO;
import net.datasa.web5.service.MemberService;

/**
 * 회원정보 관련 Controller
 * */

@Slf4j
@RequestMapping("member")
@RequiredArgsConstructor
@Controller
public class MemberController {
	private final MemberService memberService;
	
	/**
	 * 회원가입 양식으로 이동
	 * */
	@GetMapping("joinForm")
	public String join() {
		return "memberView/joinForm";
	}
	
	@PostMapping("join")
	public String join(@ModelAttribute MemberDTO member) {
		log.debug("전달된 회원정보 : {}", member);
		
		// 서비스로 전달하여 저장
		memberService.memberJoin(member);
		
		return "redirect:/";
	}
}

 

 

(8) [src/main/resources] - [templates.memberView] 안에 joinForm.html 파일 생성 후 아래와 같이 작성

<!DOCTYPE html>
<html xmlns:th="http://thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
	<meta charset="UTF-8">
	<title>회원가입</title>
	<style>
		#joinArea {
			width: 700px;
			margin: 0 auto;
			text-align: center;
		}
		
		#joinForm {
			display: flex;
			flex-direction: column;
			justify-content: center;
		}
		
				
		#formArea {
			display: flex;
			justify-content: center;
		}
		
		table, tr, td {
			border: 2px solid black;
        	border-collapse: collapse;
        	padding: 10px;
        	margin: 20px 0 15px 0;
		}
		
		th {
			width: 100px;
			background-color: grey;
			color: white;
		}
		
		td {
			width: 300px;
			text-align: left;
		}
		
		#idCheckBtn {
			margin-left: 20px;
		}
		
		td > .memberInfo {
			height: 25px;
		}
		
		#pwInputCol > div {
			height: 10px;
		}
		
		td > #address {
			width: 260px;
			height: 25px;
		}
		
	</style>
	<script th:src="@{/js/jquery-3.7.1.min.js}"></script>
	<script>
	$(document).ready(function() {
		$("#joinForm").submit(check);
	});
	
	function check() {
		let id = $("#memberId").val();
		let pw = $("#memberPassword").val();
		let pw2 = $("#memberPwCheck").val();
		let name = $("#memberName").val();
		
		if (id.length < 3 || id.length > 10) {
			alert("ID는 3자 이상 10자 이하의 글자를 반드시 입력해주세요!!");
			$("#memberId").focus();
			$("#memberId").val('');
			
	        return false;
		}
		
		if (pw.length < 8 || pw.length > 12) {
			alert("비밀번호는 8자 이상 12자 이하의 글자를 반드시 입력해주세요!!");
			$("#memberPassword").focus();
			$("#memberPassword").val('');
			
	        return false;
		}
		
		if (pw != pw2) {
			alert("입력하신 비밀번호가 일치하지 않습니다.\n확인 후 다시 입력해주세요!!");
			$("#memberPwCheck").focus();
			$("#memberPwCheck").val('');
			
	        return false;
		}
		
		if (name.length == 0) {
			alert("이름은 반드시 입력해주세요!!");
			$("#memberName").focus();
			$("#memberName").val('');
			
	        return false;
		}
		
		return true;
		
	}
	
	</script>
</head>
<body>
	<div id="joinArea">
		<h1>[ 회원가입 ]</h1>
		<form th:action="@{/member/join}" method="post" id="joinForm">
			<div id="formArea">
				<table>
					<tr>
						<th>
							<label for="memberId">ID</label>
						</th>
						<td>
							<input type="text" name="memberId" id="memberId" class="memberInfo" placeholder="ID 중복확인 이용" />
							<input type="button" id="idCheckBtn" value="ID 중복확인">
						</td>
					</tr>
					<tr>
						<th>
							<label for="memberPassword">비밀번호</label>
						</th>
						<td id="pwInputCol">
							<input type="password" name="memberPassword" id="memberPassword" class="memberInfo" placeholder="비밀번호 입력" />
							<br>
							<div></div>
							<input type="password" id="memberPwCheck" class="memberInfo" placeholder="비밀번호 다시 입력" />
						</td>
					</tr>
					<tr>
						<th>
							<label for="memberName">이름</label>
						</th>
						<td>
							<input type="text" name="memberName" id="memberName" class="memberInfo" placeholder="이름 입력" />
						</td>
					</tr>
					<tr>
						<th>
							<label for="email">이메일</label>
						</th>
						<td>
							<input type="text" name="email" id="email" class="memberInfo" placeholder="이메일 입력" />
						</td>
					</tr>
					<tr>
						<th>
							<label for="phone">전화번호</label>
						</th>
						<td>
							<input type="text" name="phone" id="phone" class="memberInfo" placeholder="전화번호 입력" />
						</td>
					</tr>
					<tr>
						<th>
							<label for="address">주소</label>
						</th>
						<td>
							<input type="text" name="address" id="address" placeholder="주소 입력" />
						</td>
					</tr>
				</table>
			</div>
			
	        <div id="btnArea">
	        	<input type="submit" value="가입" />
	        	<input type="reset" value="다시 쓰기" />
	        </div>
		</form>
	</div>
</body>
</html>

 

 

(9) 결과 화면

첫 접속 화면

 

 

"회원가입" 문구 클릭 시 화면

 

 

 

- "가입" 전 화면

 

 

 

- "가입" 후 화면