I T H

[포트폴리오 프로젝트 4] 회원가입 페이지 구현 본문

Spring MyPortfolio Project

[포트폴리오 프로젝트 4] 회원가입 페이지 구현

thdev 2024. 1. 24. 10:21
사용자 로그인 페이지를 구현하기 전에 사용자로 등록할 수 있는 회원가입 페이지를 구현하고자 한다. 사용자 정보는 아이디 중복체크만 진행하여 받도록 처리한다.

 스프링 시큐리티 설정을 완료한 상태로 가정하고 진행한다.  스프링 시큐리티는 연습용 프로젝트를 참고

[ 테이블 생성 ]

- 사용자 정보를 저장하기 위한 데이터베이스 테이블을 1개 생성한다.

CREATE TABLE `TBL_USER_INFO` (
  `USER_ID` varchar(20) NOT NULL,
  `USER_PWD` varchar(100) NOT NULL,
  `USER_NAME` varchar(100) DEFAULT NULL,
  `USER_AUTH` char(1) DEFAULT NULL,
  `USER_TEL` varchar(20) DEFAULT NULL,
  `USER_EMAIL` varchar(50) DEFAULT NULL,
  `INPUT_DATETIME` datetime DEFAULT NULL,
  PRIMARY KEY (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

[ 프론트엔드 구성 - 회원가입 페이지 구현 ]

- 회원가입 페이지 JSP 를 구현하기 전

CSS, 메뉴 영역 등 공통으로 사용될 화면에 대한 파일을 따로 정리하여 둔다.

신규 화면이 구성될 때마다 include하여 사용하도록 하여 동일한 코드를 여러 번 반복하여 사용하지 않도록 하기 위함이다.

- 아래와 같이 inc 폴더 아래에 파일 구성을 해준다. (src\main\webapp\resources\inc)

 

 

ㄱ. footer.jsp

 

- 내용은 템플릿에 있는 내용 그대로 가져와서 붙여 넣는다. 추후 문구나 스타일은 변경하여 사용할 예정이다.

<!-- 하단 푸터와 간격을 조금 벌리기 위해 -->
<br/><br/>
		
<footer id="footer">
	<div class="container">
		<div class="row">
			<div class="col-md-3 widget">
				<h3 class="widget-title">Contact</h3>
				<div class="widget-body">
					<p>+234 23 9873237<br>
						<a href="mailto:#">some.email@somewhere.com</a><br>
						<br>
						234 Hidden Pond Road, Ashland City, TN 37015
					</p>	
				</div>
			</div>

			<div class="col-md-3 widget">
				<h3 class="widget-title">Follow me</h3>
				<div class="widget-body">
					<p class="follow-me-icons">
						<a href=""><i class="fa fa-twitter fa-2"></i></a>
						<a href=""><i class="fa fa-dribbble fa-2"></i></a>
						<a href=""><i class="fa fa-github fa-2"></i></a>
						<a href=""><i class="fa fa-facebook fa-2"></i></a>
					</p>
				</div>
			</div>

			<div class="col-md-3 widget">
				<h3 class="widget-title">Text widget</h3>
				<div class="widget-body">
					<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Atque, nihil natus explicabo ipsum quia iste aliquid repellat eveniet velit ipsa sunt libero sed aperiam id soluta officia asperiores adipisci maxime!</p>
					<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Atque, nihil natus explicabo ipsum quia iste aliquid repellat eveniet velit ipsa sunt libero sed aperiam id soluta officia asperiores adipisci maxime!</p>
				</div>
			</div>

			<div class="col-md-3 widget">
				<h3 class="widget-title">Form widget</h3>
				<div class="widget-body">
					<p>+234 23 9873237<br>
						<a href="mailto:#">some.email@somewhere.com</a><br>
						<br>
						234 Hidden Pond Road, Ashland City, TN 37015
					</p>	
				</div>
			</div>

		</div> <!-- /row of widgets -->
	</div>
</footer>

<footer id="underfooter">
	<div class="container">
		<div class="row">
			
			<div class="col-md-6 widget">
				<div class="widget-body">
					<p>234 Hidden Pond Road, Ashland City, TN 37015 </p>
				</div>
			</div>

			<div class="col-md-6 widget">
				<div class="widget-body">
					<p class="text-right">
						Copyright &copy; 2014, Your awesome name here<br> 
						Design: <a href="http://www.gettemplate.com" rel="designer">Initio by GetTemplate</a> </p>
				</div>
			</div>

		</div> <!-- /row of widgets -->
	</div>
</footer>

 

ㄴ. header.jsp

 

-   css 파일들을 아래에 정리하여 준다.

<head>
	<meta charset="utf-8">
	<meta name="viewport"    content="width=device-width, initial-scale=1.0">
	<meta name="description" content="">
	<meta name="author"      content="Sergey Pozhilov (GetTemplate.com)">
	
	<title> TH's 포트폴리오 </title>

	<link rel="shortcut icon" href="/resources/images/gt_favicon.png">
	
	<!-- Bootstrap -->
	<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.no-icons.min.css" rel="stylesheet">
	<!-- Icons -->
	<link href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
	<!-- Fonts -->
	<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Alice|Open+Sans:400,300,700">
	<!-- Custom styles -->
	<link rel="stylesheet" href="/resources/css/styles.css">

	<!--[if lt IE 9]> <script src="/resources/js/html5shiv.js"></script> <![endif]-->
	<link rel="stylesheet" href="/resources/lightslider/css/lightslider.css">
</head>

 

ㄷ. incJs.jsp

 

-   javascript 파일들을 정리하여 준다.   "/resources/js/util.js” 추가 -> javaConfig연습용에 있음.

<!-- JavaScript libs are placed at the end of the document so the pages load faster -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="/resources/lightslider/js/lightslider.js"></script>
<script src="/resources/js/template.js"></script>
<script src="/resources/js/util.js"></script>
<script src="/resources/js/index.js"></script>

 

ㄹ. top.jsp

 

-   화면 상단의 메뉴 구성을 파일로 따로 분리하여 준다.

<header id="header">
	<div id="head" class="parallax" parallax-speed="2">
		<h1 id="logo" class="text-center">
			<img id="profileImg" class="img-circle" src="/resources/images/profile/20230627165120.jpeg" alt="">
			<span id="profileName" class="title">Anthony Russel</span>
			<span id="profileJob" class="tagline">A mystery person</span>
			<span class="tagline"><a id="profileEmail" href="">anthony.russel42@example.com</a></span>
		</h1>
	</div>

	<nav class="navbar navbar-default navbar-sticky">
		<div class="container-fluid">
			
			<div class="navbar-header">
				<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button>
			</div>
			
			<div class="navbar-collapse collapse">
				
				<ul class="nav navbar-nav">
					<li class="active"><a href="/">Home</a></li>
					<li><a href="about.html">About</a></li>
					<li class="dropdown">
						<a href="#" class="dropdown-toggle" data-toggle="dropdown">More Pages <b class="caret"></b></a>
						<ul class="dropdown-menu">
							<li><a href="sidebar-left.html">Left Sidebar</a></li>
							<li><a href="sidebar-right.html">Right Sidebar</a></li>
							<li><a href="single.html">Blog Post</a></li>
						</ul>
					</li>
					<li><a href="blog.html">Blog</a></li>
				</ul>
			
			</div><!--/.nav-collapse -->			
		</div>	
	</nav>
</header>

 

- Index.jsp 태그 추가 

<%@include file="/resources/inc/top.jsp"%>
<%@include file="/resources/inc/incJs.jsp"%>

 

- 파일 정리 후 [ index.jsp ]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="kr">
<link rel="stylesheet" href="/resources/lightslider/css/lightslider.css">
<%@include file="/resources/inc/header.jsp"%>
<body class="home">
	<%@include file="/resources/inc/top.jsp"%>
	
	<main id="main">
		<div class="container">
			<div class="row section topspace">
				<div class="col-md-12">
					<p class="lead text-center text-muted">Let me tell you something my friend. hope is a dangerous thing. hope can drive a man insane. you <a href="about.html">measure</a> yourself by the people who measure themselves by you. it only took me <a href="sidebar-right.html">six days</a>. </p>
				</div>
			</div> <!-- / section -->
			
			<div class="row section featured topspace">
				<h2 class="section-title"><span>Services</span></h2>
				<div class="row">
					<div class="col-sm-6 col-md-3">
						<h3 class="text-center">Custom website design</h3>
						<p>I don't think they tried to market it to the billionaire, spelunking, base-jumping crowd. i did the same thing to gandhi, he didn't eat for three weeks. i once heard a wise man say there are no perfect men.</p>
						<p class="text-center"><a href="" class="btn btn-action">Read more</a></p>
					</div>
					<div class="col-sm-6 col-md-3">
						<h3 class="text-center">Wordpress integration</h3>
						<p>I don't think they tried to market it to the billionaire, spelunking, base-jumping crowd. i did the same thing to gandhi, he didn't eat for three weeks. i once heard a wise man say there are no perfect men.</p>
						<p class="text-center"><a href="" class="btn btn-action">Read more</a></p>
					</div>
					<div class="col-sm-6 col-md-3">
						<h3 class="text-center">Application development</h3>
						<p>I don't think they tried to market it to the billionaire, spelunking, base-jumping crowd. i did the same thing to gandhi, he didn't eat for three weeks. i once heard a wise man say there are no perfect men.</p>
						<p class="text-center"><a href="" class="btn btn-action">Read more</a></p>
					</div>
					<div class="col-sm-6 col-md-3">
						<h3 class="text-center">SEO &amp; SEM services</h3>
						<p>I don't think they tried to market it to the billionaire, spelunking, base-jumping crowd. i did the same thing to gandhi, he didn't eat for three weeks. i once heard a wise man say there are no perfect men.</p>
						<p class="text-center"><a href="" class="btn btn-action">Read more</a></p>
					</div>
				</div>
			</div> <!-- / section -->
		
			<div class="row section recentworks topspace">
				
				<h2 class="section-title"><span>Recent Works</span></h2>
				
				<div class="thumbnails recentworks row">
					
					<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
						<a class="thumbnail" href="sidebar-right.html">
							<span class="img">
								<img src="resources/images/s1.jpg" alt="">
								<span class="cover"><span class="more">See details &rarr;</span></span>
							</span>
							<span class="title">Sample title - big data solutions</span>
						</a>
						<span class="details"><a href="">Web design</a> | <a href="">Wordpress</a> | <a href="">Logotype</a></span>
						<h4></h4>
						<p></p>
					</div>
					
					<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
						<a class="thumbnail" href="sidebar-right.html">
							<span class="img">
								<img src="resources/images/s1.jpg" alt="">
								<span class="cover"><span class="more">See details &rarr;</span></span>
							</span>
							<span class="title">Pure ipsum - development services for people</span>
						</a>
						<span class="details"><a href="">Web design</a> | <a href="">Wordpress</a></span>
						<h4></h4>
						<p></p>
					</div>
					
					<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
						<a class="thumbnail" href="sidebar-right.html">
							<span class="img">
								<img src="resources/images/s1.jpg" alt="">
								<span class="cover"><span class="more">See details &rarr;</span></span>
							</span>
							<span class="title">Lorem studios - interior and patio design</span>
						</a>
						<span class="details"><a href="">Web design</a> | <a href="">Logotype</a></span>
						<h4></h4>
						<p></p>
					</div>
	
					<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
						<a class="thumbnail" href="sidebar-right.html">
							<span class="img">
								<img src="resources/images/s1.jpg" alt="">
								<span class="cover"><span class="more">See details &rarr;</span></span>
							</span>
							<span class="title">Pure ipsum - development services for people</span>
						</a>
						<span class="details"><a href="">Web design</a> | <a href="">Wordpress</a></span>
						<h4></h4>
						<p></p>
					</div>
					
					<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
						<a class="thumbnail" href="sidebar-right.html">
							<span class="img">
								<img src="resources/images/s1.jpg" alt="">
								<span class="cover"><span class="more">See details &rarr;</span></span>
							</span>
							<span class="title">Lorem studios - interior and patio design</span>
						</a>
						<span class="details"><a href="">Web design</a> | <a href="">Logotype</a></span>
						<h4></h4>
						<p></p>
					</div>
	
					<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
						<a class="thumbnail" href="sidebar-right.html">
							<span class="img">
								<img src="resources/images/s1.jpg" alt="">
								<span class="cover"><span class="more">See details &rarr;</span></span>
							</span>
							<span class="title">Lorem studios - interior and patio design</span>
						</a>
						<span class="details"><a href="">Web design</a> | <a href="">Logotype</a></span>
						<h4></h4>
						<p></p>
					</div>
				</div>
	
			</div> <!-- /section -->
	
			<div class="row section topspace">
				<div class="panel panel-cta"><div class="panel-body">
					<div class="col-lg-8">
						<p>A simple, nice-looking <b>call to action box</b>. Boxing is about respect. getting it for yourself, 
						and taking it away from the other guy. no, this is mount everest. </p>
					</div>
					<div class="col-lg-4 text-right">
						<a href="http://www.gettemplate.com/downloads/initio.zip " class="btn btn-primary btn-lg">Download template</a>
					</div>
				</div></div>
			</div> <!-- /section -->
	
			<div class="row section clients topspace">
				<h2 class="section-title"><span>LANGUAGE</span></h2>
				<ul id="lightSlider" class="gallery">
					<li><img src="/resources/images/carousel/jquery.png" /></li>
					<li><img src="/resources/images/carousel/java.png" /></li>
					<li><img src="/resources/images/carousel/bootstrap.png" /></li>
					<li><img src="/resources/images/carousel/spring.png" /></li>
					<li><img src="/resources/images/carousel/react.jpg" /></li>
					<li><img src="/resources/images/carousel/mysql.png" /></li>
					<li><img src="/resources/images/carousel/oracle.png" /></li>
				</ul>
			</div> <!-- /section -->
		<br/><br/>
		</div>	<!-- /container -->
	</main>
	
	<%@include file="/resources/inc/footer.jsp"%>
	<%@include file="/resources/inc/incJs.jsp"%>
</body>
</html>

 

ㅁ. register.jsp (src\main\webapp\WEB-INF\views\register.jsp)

 

- 회원가입을 위한 정보를 입력 받을 페이지를 구현한다.

- 위에서 작성한 ㄱ~ㄹ 파일들을 페이지에 include하여 코드가 간결하게 보이도록 처리하는 것이 이번 장에 핵심이다.

- 추가로 해당 화면에서만 사용될 스크립트 파일을 따로 작성하여 include하여 사용하는 방식을 취한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="kr">
<%@include file="/resources/inc/header.jsp"%>

<style>
.row {
	justify-content: center;
	display: flex;
	padding: 5px;
}
</style>
<body class="home">
	<%@include file="/resources/inc/top.jsp"%>

	<main id="main">

		<div class="container">

			<div class="section featured topspace">
				<h2 class="section-title">
					<span>회원 등록 페이지</span>
				</h2>
				<div class="row">
					<div class="col-sm-6 col-md-6">
						<h3 class="text-center">회원 등록 정보를 입력하세요.</h3>
						<p>아이디를 비롯한 필수항목은 입력한 후 가입을 해야 정상 가입이 됩니다.</p>
					</div>
				</div>
				<div style="" class="col-md-4 col-sm-4"></div> <!-- 빈 div 태그로 여백주기 -->
				<div class="col-md-4 col-sm-4"
					style="border: 1px solid #c5cfcb; border-radius: 5px; padding: 15px;">
					<div class="row">
						<div class="col-sm-12 col-md-12">
							<label class="form-label" for="txtId">아이디 *</label> <input
								type="text" id="txtId" class="form-control"> <br /> <a
								id="btnDuplicate" class="btn w-btn-green button-hover">중복 체크</a>
						</div>
					</div>

					<div class="row">
						<div class="col-sm-12 col-md-12">
							<label class="form-label" for="txtPassword">비밀번호 *</label> <input
								type="password" id="txtPassword" class="form-control">
						</div>
					</div>

					<div class="row">
						<div class="col-sm-12 col-md-12">
							<label class="form-label" for="txtPassword2">비밀번호 재입력 *</label> <input
								type="password" id="txtPassword2" class="form-control">
						</div>
					</div>

					<div class="row">
						<div class="col-sm-12 col-md-12">
							<label class="form-label" for="txtName">성명</label> <input
								type="text" id="txtName" class="form-control">
						</div>
					</div>

					<div class="row">
						<div class="col-sm-12 col-md-12">
							<label class="form-label" for="txtTel">전화번호</label> <input
								type="text" id="txtTel" class="form-control">
						</div>
					</div>

					<div class="row">
						<div class="col-sm-12 col-md-12">
							<label class="form-label" for="txtEmail">이메일</label> <input
								type="text" id="txtEmail" class="form-control">
						</div>
					</div>

					<br />
					<div class="row">
						<div class="text-center col-sm-12 col-md-12">
							<a id="btnRegister" class="btn btn-block w-btn-green button-hover">회원등록</a>
						</div>
					</div>
				</div>
			</div>
			<!-- / section -->

		</div>
		<!-- /container -->

	</main>


	<%@include file="/resources/inc/footer.jsp"%>
	<%@include file="/resources/inc/incJs.jsp"%>

	<!-- page script -->
	<script src="/resources/views/register.js"></script>

</body>
</html>

 

- Dependency 추가

 

- 파일 업로드를 위한 라이브러리를 참조하기 위해 pom.xml 파일에 아래 내용을 추가한다.

참고 > https://commons.apache.org/proper/commons-fileupload/

 

FileUpload – Home

Commons FileUpload The Commons FileUpload package makes it easy to add robust, high-performance, file upload capability to your servlets and web applications. FileUpload parses HTTP requests which conform to RFC 1867, "Form-based File Upload in HTML". That

commons.apache.org

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>

 

ㅂ. register.js

 

 src\main\webapp\resources\views\register.js

- 스크립트에는 버튼 클릭 이벤트 및 컨트롤러 호출에 대한 ajax 코드를 담고 있으며,

해당 스크립트는 페이지가 로드된 시점에 자동으로 호출된다.

/*******************************************************************************
 * register.js
 * @author thevalue
 * @since 2023
 * @DESC 회원가입 화면 스크립트
 ******************************************************************************/

 (function(){
	 function Register(){
		 //private variables
		 var dupliComplete = false; //아이디 중복 확인용 변수
		 
		 //초기화 메서드
		 function _init(){
			 //이벤트 처리 함수 호출
			 bindEvent();
		 }
		 
		 function bindEvent(){
			 
			 // 가입 버튼 클릭 이벤트
			$("#btnRegister").on("click", function() {
				// validation check
				var obj = validationCheck();
				if(!obj){
					return;
				}
				if(dupliComplete) {
					cfSave("/register/saveAccountInfo.do", obj, function(data) {
						if(data.success) {
							alert("사용자 등록이 완료되었습니다. 로그인 페이지로 이동합니다.");
							setTimeout(function() {
								window.location.href = "/login";
							}, 2000);
						}
					}, true, "POST");
				} 
				
				if(obj && !dupliComplete) {
					alert("사용자 계정 중복확인을 진행 후 시도하시기 바랍니다.");
					return;
				}
			});
			
			// duplicate 버튼 클릭 시 (아이디중복확인)
			$("#btnDuplicate").on("click", function() {
				var valid = true;
				
				var txtId = $("#txtId").val();
				if(txtId == "" || txtId == null) {
					alert("아이디를 입력하시기 바랍니다.");
					return;
				}
				
				if(valid) {
					var obj = {
						id : txtId
					};
					
					cfFind("/register/findUserId.do", obj, function(data) {
						if(data.length > 0) {
							alert("이미 사용중인 계정입니다.");
							return;
						} else {
							alert("사용 가능한 아이디입니다.");
							// 입력한 계정정보가 존재하지 않는 경우 체크 완료 표시
							$("#btnDuplicate").attr("disabled", true);
							$("#txtId").attr("disabled", true);
							
							dupliComplete = true;
						}
					}, true, "POST");
				}
			});
			
			
		 }//bindEvent
		 
		 /*
		 * 사용자 입력 폼 필수 값 등 validation check
		 * 일반적인 사용자 등록 시 
		 */
		 function validationCheck(){
			 var obj = {};
			
			if($("#txtId").val() == null || $("#txtId").val() == "") {
				alert("사용자 아이디를 입력하시기 바랍니다.");
				$("#txtId").focus();
				return false;
			}
			obj.userId = $("#txtId").val();
			obj.userAuth = "1"; // 일반사용자 권한
			
			if($("#txtName").val() == null || $("#txtName").val() == "") {
				alert("사용자명을 입력하시기 바랍니다.");
				$("#txtName").focus();
				return false;
			}
			obj.userName = $("#txtName").val();
			
			if($("#txtEmail").val() == null || $("#txtEmail").val() == "") {
				alert("이메일을 입력하시기 바랍니다.");
				$("#txtEmail").focus();
				return false;
			} else {
				//이메일 형식 체크
				/*var emailRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
				var result = checkRegexp($("#txtEmail"),emailRegex);
				if(!result){
					alert("이메일 형식을 확인하세요.");
					return false;
				}*/
				
				var reg_email = /^([0-9a-zA-Z_\.-]+)@([0-9a-zA-Z_-]+)(\.[0-9a-zA-Z_-]+){1,2}$/;
			     if(!reg_email.test($("#txtEmail").val())) {   
					alert("이메일 형식을 확인하세요.");                         
			        return false;         
			     }			}
			obj.userEmail = $("#txtEmail").val();
			
			var password1 = $("#txtPassword").val();
			var password2 = $("#txtPassword2").val();
			
			if(password1.length < 8) {
				alert("비밀번호는 8자리 이상으로 설정하시기 바랍니다.");
				return false;
			}
			if(password1 != password2) {
				alert("비밀번호가 일치하지 않습니다.");
				return false;
			}
			obj.userPwd = password1;
			
			if($("#txtTel").val() == null || $("#txtTel").val() == "") {
				alert("전화번호를 입력하시기 바랍니다.");
				$("#txtTel").focus();
				return false;
			}
			obj.userTel = $("#txtTel").val();
			
			return obj;
		}
		 
		 
		 
		 function _finalize(){
			 
		 }
		 
		 return {
			 init : _init,
			 finalize: _finalize
		 }
	 }
	 
	 var register = new Register();
	 register.init();
 })();

 

[  백앤드구성 

- ajax에서 컨트롤러 호출 후 데이터베이스까지 파라미터 전달할때 모델빈 사용

- 시큐리티 비밀번호 암호화기능 사용

[ domain 모델 빈 ]

-   kr\co\values\login\domain\User.java

package kr.co.values.login.domain;

/*
 * 사용자 테이블 컬럼 구조 
 *  `USER_ID` varchar(20) NOT NULL,
  `USER_PWD` varchar(100) NOT NULL,
  `USER_NAME` varchar(100) DEFAULT NULL,
  `USER_AUTH` char(1) DEFAULT NULL,
  `USER_TEL` varchar(20) DEFAULT NULL,
  `USER_EMAIL` varchar(50) DEFAULT NULL,
  `INPUT_DATETIME` datetime DEFAULT NULL,
 */
public class User {
	private String userId;
	private String userPwd;
	private String userName;
	private String userAuth;
	private String userTel;
	private String userEmail;
	
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserPwd() {
		return userPwd;
	}
	public void setUserPwd(String userPwd) {
		this.userPwd = userPwd;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getUserAuth() {
		return userAuth;
	}
	public void setUserAuth(String userAuth) {
		this.userAuth = userAuth;
	}
	public String getUserTel() {
		return userTel;
	}
	public void setUserTel(String userTel) {
		this.userTel = userTel;
	}
	public String getUserEmail() {
		return userEmail;
	}
	public void setUserEmail(String userEmail) {
		this.userEmail = userEmail;
	}
	
	
}

[ 컨트롤러 구현 ]

kr\co\values\register\web\RegisterController.java 파일을 생성하여 아래 내용을 입력한다.

package kr.co.values.register.web;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.co.values.login.domain.User;
import kr.co.values.register.persistence.RegisterMapper;
import kr.co.values.register.service.RegisterService;

@Controller
public class RegisterController {
	
	@Autowired
	private RegisterMapper registerMapper;
	
	@Autowired
	private RegisterService registerService;
	
    @RequestMapping("/register.do")
    public String main() {
    	
    	System.out.println("회원 가입 페이지로 이동");
    	
        return "register";
    }
    
    /**
	 * 사용자 아이디 중복 체크 
	 * (/register/findUserId)
	 * @return
	 */
	@RequestMapping("/register/findUserId.do")
	@ResponseBody
	public List<Map<String, Object>> findUserId(@RequestBody Map<String, Object> param) {
		List<Map<String, Object>> list = registerMapper.findUserId(param);
		
		return list;
	}
	
	/**
	 * 사용자 신규 저장
	 * (/register/saveAccountInfo)
	 * @return
	 */
	@RequestMapping("/register/saveAccountInfo.do")
	@ResponseBody
	public Map<String, Object> saveAccountInfo(@RequestBody User user) {
		Map<String, Object> result = new HashMap<String, Object>();
		registerService.saveAccountInfo(user);
		
		result.put("success", true);
		return result;
	}
    
}

[ 서비스 구현 ]

kr\co\values\register\service\RegisterService.java 파일을 생성한다.

package kr.co.values.register.service;

import kr.co.values.login.domain.User;

public interface RegisterService {
	
	void saveAccountInfo(User map);
}

kr\co\values\register\service\RegisterServiceImpl.java 파일을 생성한다.

passwordEncoder 를 통해 비밀번호 암호화 로직이 포함되어 있다.

 

그 전에 시큐리티 패키지 설정을 먼저 하도록 함.

kr.co.values.security패키지를 만들고 SecurityConfig.java 파일을 작성한다.

package kr.co.values.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;



/* Spring Security를 이용해 로그인/로그아웃/인증/인가 등을 처리하기 위한 설정 파일이다.
 * @EnableWebSecurity가 붙어 있을 경우 Spring Security를 구성하는 기본적인 Bean들을 자동으로 구성해준다.
 * WebSecurityConfigurerAdapter를 상속받으면 특정 메소드를 오버라이딩 함으로써 좀 더 손쉽게 설정할 수 있다.
 */

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	/* 
	 * 주의) configure() 메소드는 파라미터 타입이 다른 동일한 메소드명이 존재하므로 확인 필수
	 * 인증 및 인가가 필요없는 url 을 지정하여 시큐리티 미적용되도록 처리한다.
	 * ex > /resources /css /img 등등
	 */
	
	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/webjars/**");
	}
	
	/* configure(HttpSecurity http) 메소드를 오버라이딩 한다는 것은 인증/인가에 대한 설정을 한다는 의미이다. 
     * 가장 중요한 메소드로 볼 수 있다.
     *
     * http.csrf().disable()는 csrf() 기능을 끄라는 설정이다.
     * csrf는 보안 설정 중 post방식으로 값을 전송할 때 token을 사용해야하는 보안 설정이다.
     * csrf은 기본으로 설정되어 있는데 사용시 보안성은 높아지지만 
     * 개발초기에는 불편함이 있다는 단점이 있어서 기능을 끈 것이다.
     */
	

	
	 /*
     * 비밀번호 암호화를 위해 사용한다.
     */
	@Bean
	public PasswordEncoder encoder() {
		return new BCryptPasswordEncoder();
	}
	
}

[ RegisterServiceImpl.java ]

package kr.co.values.register.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import kr.co.values.login.domain.User;
import kr.co.values.register.persistence.RegisterMapper;

@Service
public class RegisterServiceImpl implements RegisterService {

	@Autowired
	private RegisterMapper registerMapper;
	
	@Autowired
	private PasswordEncoder passwordEncoder; 

	@Override
	public void saveAccountInfo(User userInfo) {
		
		String orgPassword = userInfo.getUserPwd();
		String userId = userInfo.getUserId();
		String decPassword = initUserPassword(orgPassword, userId);
		
		userInfo.setUserPwd(decPassword);
		
		registerMapper.saveAccountInfo(userInfo);
	}
	
	private String initUserPassword(String orgPassword, String userId) {
        return passwordEncoder.encode(orgPassword);
    }

	
}

[ 매퍼 구현 ]

kr\co\values\register\persistence\RegisterMapper.java 파일을 생성한다.

package kr.co.values.register.persistence;

import java.util.List;
import java.util.Map;

import kr.co.values.login.domain.User;

public interface RegisterMapper {
	
	// 사용자 정보 조회
	List<Map<String, Object>> findUserId(Map<String, Object> params);
		
	// 사용자 등록
	void saveAccountInfo(User params);
	
}

 

kr\co\values\register\persistence\RegisterMapper.xml 파일을 생성한다.

사용자 등록 쿼리에는 파라미터로 Map 형태가 아닌 모델빈을 통해 전달받도록 설정을 해보았다.

<?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="kr.co.values.register.persistence.RegisterMapper">

	<select id="findUserId" resultType="hashmap" parameterType="hashmap">
		SELECT * 
		  FROM TBL_USER_INFO
		 WHERE 1=1
		   AND USER_ID = #{id}
	</select>
	
	<insert id="saveAccountInfo" parameterType="kr.co.values.login.domain.User">
		INSERT INTO TBL_USER_INFO (
				USER_ID
			  , USER_PWD
			  , USER_NAME
			  , USER_AUTH
			  , USER_TEL
			  , USER_EMAIL
			  , INPUT_DATETIME
		)
		VALUES (
			  #{userId}
			, #{userPwd}
			, #{userName}
			, #{userAuth}
			, #{userTel}
			, #{userEmail}
			, NOW()
		)
	</insert>
	
</mapper>

 

- 모델 빈을 통해 파라미터로 받을 경우 변수명과 쿼리 매핑 시 컬럼을 일치시켜줘야 한다

 

[ 실행 결과 ]

 

-   /register.do 로 접속 후 테스트