I T H

[프로젝트] 8. 화면개발 - 회원가입 페이지 구현 (Week 2) 본문

Spring ArtGallery Project

[프로젝트] 8. 화면개발 - 회원가입 페이지 구현 (Week 2)

thdev 2024. 1. 23. 10:49

데이터베이스 생성 및 테이블 설계를 완료한 후

지난번까지 진행한 기본 설정이 끝난 프로젝트를 통해 회원가입 페이지를 구현. 

 

먼저 회원가입 페이지 (템플릿을 이용한 모든 페이지)에 사용될 로고를 먼저 만들어보자.

무료로 로고 이미지를 제작해주는 사이트가 많으므로 그 중 하나를 골라서  Pick!

(참고 사이트 : https://www.canva.com )

 

사이트에 들어갈 로고

 

하단 로고

 

favicon 이미지로 사용할 이미지도 같이 만듬.

 

- 파비콘

템플릿을 통한 화면 UI 구성

css, js, footer 영역을 별도의 jsp로 빼서 

임포트 하는 방식으로 선택 

추가로 개발되는 페이지에서도 소스 코드 재작성없이 사용할 수 있도록 하기 위함.

 

[ css 파일 ]

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!-- Favicon  -->
<link rel="icon" href="/resources/img/core-img/favicon.png">

<!-- Core Style CSS -->
<link rel="stylesheet" href="/resources/css/core-style.css">
<link rel="stylesheet" href="/resources/css/style.css">

<!-- Search Wrapper Area Start -->
<div class="search-wrapper section-padding-100">
    <div class="search-close">
        <i class="fa fa-close" aria-hidden="true"></i>
    </div>
    <div class="container">
        <div class="row">
            <div class="col-12">
                <div class="search-content">
                    <form action="#" method="get">
                        <input type="search" name="search" id="search" placeholder="Type your keyword...">
                        <button type="submit"><img src="/resources/img/core-img/search.png" alt=""></button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- Search Wrapper Area End -->

 

[ js 파일 ]

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!-- ##### jQuery (Necessary for All JavaScript Plugins) ##### -->
<script src="/resources/js/jquery/jquery-2.2.4.min.js"></script>
<!-- Popper js -->
<script src="/resources/js/popper.min.js"></script>
<!-- Bootstrap js -->
<script src="/resources/js/bootstrap.min.js"></script>
<!-- Plugins js -->
<script src="/resources/js/plugins.js"></script>
<!-- Active js -->
<script src="/resources/js/active.js"></script>
<!-- Util js ajax call 함수로 생성하여 호출하도록 함 -->
<script src="/resources/js/util.js"></script>

 

[ footer 영역 ]

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!-- ##### Newsletter Area Start ##### -->
<section class="newsletter-area section-padding-100-0">
    <div class="container">
        <div class="row align-items-center">
            <!-- Newsletter Text -->
            <div class="col-12 col-lg-6 col-xl-7">
                <div class="newsletter-text mb-100">
                    <h2>Subscribe for a <span>25% Discount</span></h2>
                    <p>TH Art Gallery 최신 뉴스 및 정보를 구독하세요.</p>
                </div>
            </div>
            <!-- Newsletter Form -->
            <div class="col-12 col-lg-6 col-xl-5">
                <div class="newsletter-form mb-100">
                    <form action="#" method="post">
                        <input type="email" name="email" class="nl-email" placeholder="Your E-mail">
                        <input type="submit" value="Subscribe">
                    </form>
                </div>
            </div>
        </div>
    </div>
</section>
<!-- ##### Newsletter Area End ##### -->

<!-- ##### Footer Area Start ##### -->
<footer class="footer_area clearfix">
    <div class="container">
        <div class="row align-items-center">
            <!-- Single Widget Area -->
            <div class="col-12 col-lg-4">
                <div class="single_widget_area">
                    <!-- Logo -->
                    <div class="footer-logo mr-50">
                        <a href="/"><img src="/resources/img/core-img/logo2.png" alt="" style="width: 160px;"></a>
                    </div>
                    <!-- Copywrite Text -->
                    <p class="copywrite">
						Copyright &copy;<script>document.write(new Date().getFullYear());</script> All rights reserved | TH Art Gallery
					</p>
                </div>
            </div>
            <!-- Single Widget Area -->
            <div class="col-12 col-lg-8">
                <div class="single_widget_area">
                    <!-- Footer Menu -->
                    <div class="footer_menu">
                        <nav class="navbar navbar-expand-lg justify-content-end">
                            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#footerNavContent" aria-controls="footerNavContent" aria-expanded="false" aria-label="Toggle navigation"><i class="fa fa-bars"></i></button>
                            <div class="collapse navbar-collapse" id="footerNavContent">
                                <ul class="navbar-nav ml-auto">
                                    <li class="nav-item active">
                                        <a class="nav-link" href="/">메인</a>
                                    </li>
                                    <li class="nav-item">
                                        <a class="nav-link" href="/prod">상품</a>
                                    </li>
                                    <li class="nav-item">
                                        <a class="nav-link" href="/board">게시판</a>
                                    </li>
                                    <li class="nav-item">
                                        <a class="nav-link" href="/cart">장바구니</a>
                                    </li>
                                    <li class="nav-item">
                                        <a class="nav-link" href="/mypage">마이페이지</a>
                                    </li>
                                </ul>
                            </div>
                        </nav>
                    </div>
                </div>
            </div>
        </div>
    </div>
</footer>
<!-- ##### Footer Area End ##### -->

 

[ header 영역 ]

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!-- Mobile Nav (max width 767px)-->
<div class="mobile-nav">
    <!-- Navbar Brand -->
    <div class="amado-navbar-brand">
        <a href="/"><img src="/resources/img/core-img/logo-th.png" alt=""></a>
    </div>
    <!-- Navbar Toggler -->
    <div class="amado-navbar-toggler">
        <span></span><span></span><span></span>
    </div>
</div>

<!-- Header Area Start -->
<header class="header-area clearfix">
    <!-- Close Icon -->
    <div class="nav-close">
        <i class="fa fa-close" aria-hidden="true"></i>
    </div>
    <!-- Logo -->
    <div class="logo">
        <a href="/"><img src="/resources/img/core-img/logo-th.png" alt=""></a>
    </div>
    <!-- Amado Nav -->
    <nav class="amado-nav">
        <ul>
            <li class="active"><a href="/">메인</a></li>
            <li><a href="/prod">상품</a></li>
            <li><a href="/board">게시판</a></li>
            <li><a href="/cart">장바구니</a></li>
            <li><a href="/mypage">마이페이지</a></li>
        </ul>
    </nav>
    <!-- Button Group -->
    <div class="amado-btn-group mt-30 mb-100">
        <a href="#" class="btn amado-btn mb-15">button1</a>
        <a href="#" class="btn amado-btn active">button2</a>
    </div>
    <!-- Cart Menu -->
    <div class="cart-fav-search mb-100">
        <a href="cart.html" class="cart-nav"><img src="/resources/img/core-img/cart.png" alt=""> Cart <span>(0)</span></a>
        <a href="#" class="fav-nav"><img src="/resources/img/core-img/favorites.png" alt=""> Favourite</a>
        <a href="#" class="search-nav"><img src="/resources/img/core-img/search.png" alt=""> Search</a>
    </div>
    <!-- Social Button -->
    <div class="social-info d-flex justify-content-between">
        <a href="#"><i class="fa fa-pinterest" aria-hidden="true"></i></a>
        <a href="#"><i class="fa fa-instagram" aria-hidden="true"></i></a>
        <a href="#"><i class="fa fa-facebook" aria-hidden="true"></i></a>
        <a href="#"><i class="fa fa-twitter" aria-hidden="true"></i></a>
    </div>
</header>
<!-- Header Area End -->

 

결과적으로 

화면 개발 시마다 공통으로 쓰이는 jsp 파일을 아래와 같이 import(include) 하여 사용할 예정.

<!DOCTYPE html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="description" content="">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- The above 4 meta tags *must* come first in the head; any other head content must come *after* these tags -->

    <!-- Title  -->
    <title>회원가입</title>
	
	<!-- import Css -->
    <%@include file="/resources/inc/incCss.jsp" %>
</head>

<body>
     <!-- ##### Main Content Wrapper Start ##### // 메인(화면전체)의 껍데기인 첫째줄은 복사해서 사용-->
    <div class="main-content-wrapper d-flex clearfix">
    
	    <!-- import Header -->
	    <%@include file="/resources/inc/incHeader.jsp" %>
    
    
    </div>
    <!-- ##### Main Content Wrapper End ##### -->
	
	<!-- import Footer -->
    <%@include file="/resources/inc/incFooter.jsp" %>
    
	<!-- import Js -->
    <%@include file="/resources/inc/incJs.jsp" %>
 
</body>
</html>

 

회원가입 페이지 샘플용

현 시점까지 폴더 구성.

 

 

inc 폴더 생성 후 공통으로 쓰이는 코드 분리


[ register.jsp ]

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	
<!DOCTYPE html>
<html lang="kr">

<head>
    <meta charset="UTF-8">
    <meta name="description" content="">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- The above 4 meta tags *must* come first in the head; any other head content must come *after* these tags -->

    <!-- Title  -->
    <title>ART - 회원가입</title>

	<!-- import CSS -->
	<%@include file="/resources/inc/incCss.jsp"%>
</head>

<body>

    <!-- ##### Main Content Wrapper Start ##### -->
    <div class="main-content-wrapper d-flex clearfix">

        <!-- import Header -->
		<%@include file="/resources/inc/incHeader.jsp"%>

        <div class="cart-table-area section-padding-100">
            <div class="container-fluid">
                <div class="row">
                    <div class="col-12 col-lg-12">
                        <div class="checkout_details_area mt-50 clearfix">

                            <div class="cart-title">
                                <h2>회원가입</h2>
                            </div>

                            <form action="#" method="post">
                                <div class="row">
                                    <div class="col-md-6 mb-3">
                                    	<small>아이디</small>
                                        <input type="text" class="form-control" id="txtId" value="" placeholder="아이디 입력" required>
                                    </div>
                                    <div class="col-md-3 mb-3">
                                    	<small>&nbsp;</small>
                                    	<div class="cart-btn">
			                                <a id="btnDuplicate" href="javascript:void(0)" class="btn amado-btn w-100">아이디 중복체크</a>
			                            </div>
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>비밀번호</small>
                                        <input type="password" class="form-control" id="txtPwd" value="" placeholder="비밀번호 입력" required>
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>비밀번호 확인</small>
                                        <input type="password" class="form-control" id="txtPwd2" value="" placeholder="비밀번호 다시 입력" required>
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>사용자명</small>
                                        <input type="text" class="form-control" id="txtName" value="" placeholder="성명 입력">
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>성별</small>
                                        <select class="w-100" id="cmbSex">
	                                        <option value="1">남자</option>
	                                        <option value="2">여자</option>
                                    	</select>
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>전화번호</small>
                                        <input type="number" class="form-control" id="txtTel" min="0" placeholder="전화번호 입력" value="">
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>이메일</small>
                                        <input type="email" class="form-control" id="txtMail" placeholder="이메일 입력" value="">
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>주소</small>
                                        <input type="text" class="form-control mb-3 txtAddrInfo" id="txtAddr" placeholder="주소 입력" value="">
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<small>우편번호</small>
                                        <input type="text" class="form-control txtAddrInfo" id="txtZipCode" placeholder="우편번호 입력" value="">
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<div class="cart-btn mt-50">
			                                <a id="btnRegister" href="javascript:void(0)" class="btn amado-btn w-100">가입</a>
			                            </div>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- ##### Main Content Wrapper End ##### -->

    <!-- import Footer -->
	<%@include file="/resources/inc/incFooter.jsp"%>

    <!-- import JS -->
	<%@include file="/resources/inc/incJs.jsp"%>
	
	<!-- 우편번호 api 사용 -->
	<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
	
	<!-- page script -->
	<script src="/resources/views/register.js"></script>

</body>

</html>

 

[ register.js ]

/*******************************************************************************
 * register.js
 * @author thkim
 * @since 2022
 * @DESC 회원가입 화면 스크립트
 ******************************************************************************/
(function() {
	
	function Register() {
		
		/* 
		 * private variables
		 */
		var dupliComplete = false; // 아이디 중복 확인용 변수
		
		/* 
		 * 초기화 메소드
		 */
		function _init() {
			// 이벤트 처리 함수 호출 
			bindEvent();
		}
		
		function bindEvent() {
			
			// 주소, 우편번호 입력란 클릭 이벤트 
			// 우편번호 api를 통해 주소찾는 팝업창 호출 
			// 검색완료 및 주소 선택 시 주소값을 입력란에 출력시켜줌
			$(".txtAddrInfo").on("click", function() {
				new daum.Postcode({
			        oncomplete: function(data) {
			            $("#txtAddr").val(data.address);
			            $("#txtZipCode").val(data.zonecode);
			        }
			    }).open();
			});
			
			// 가입 버튼 클릭 이벤트
			$("#btnRegister").on("click", function() {
				// validation check
				var obj = validationCheck();
				
				if(dupliComplete) {
					cfSave("/register/saveAccountInfo", obj, function(data) {
						if(data.success) {
							alert("사용자 등록이 완료되었습니다. 로그인 페이지로 이동합니다.");
							setTimeout(function() {
								window.location.href = "/login";
							}, 2000);
						}
					});
				} 
				
				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", obj, function(data) {
						console.log(data);
						if(data.length > 0) {
							alert("이미 사용중인 계정입니다.");
							return;
						} else {
							alert("사용 가능한 아이디입니다.");
							// 입력한 계정정보가 존재하지 않는 경우 체크 완료 표시
							$("#btnDuplicate").attr("disabled", true);
							$("#txtId").attr("disabled", true);
							
							dupliComplete = true;
						}
					}, true, "POST");
				}
			});
		}
		
		/*
		 * 사용자 입력 폼 필수 값 등 validation check
		 * 일반적인 사용자 등록 시 
		 */
		function validationCheck() {
			var obj = {};
			
			if($("#txtId").val() == null || $("#txtId").val() == "") {
				alert("사용자 아이디를 입력하시기 바랍니다.");
				$("#txtId").focus();
				return false;
			}
			obj.userId = $("#txtId").val();
			obj.authType = "1"; // 일반사용자 권한
			
			if($("#txtName").val() == null || $("#txtName").val() == "") {
				alert("사용자명을 입력하시기 바랍니다.");
				$("#txtName").focus();
				return false;
			}
			obj.userName = $("#txtName").val();
			
			if($("#txtMail").val() == null || $("#txtMail").val() == "") {
				alert("이메일을 입력하시기 바랍니다.");
				$("#txtMail").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($("#txtMail"), emailRegex);
				if(!result) {
					alert("이메일 형식을 확인하세요.");
					return false;
				}
			}
			obj.userEmail = $("#txtMail").val();
			
			var password1 = $("#txtPwd").val();
			var password2 = $("#txtPwd2").val();
			
			if(password1.length < 8) {
				alert("비밀번호는 8자리 이상으로 설정하시기 바랍니다.");
				return false;
			}
			if(password1 != password2) {
				alert("비밀번호가 일치하지 않습니다.");
				return false;
			}
			obj.userPw = password1;
			
			if($("#txtTel").val() == null || $("#txtTel").val() == "") {
				alert("전화번호를 입력하시기 바랍니다.");
				$("#txtTel").focus();
				return false;
			}
			obj.userPhone = $("#txtTel").val();
			
			// 주소, 우편번호, 성별 
			obj.userAddr = $("#txtAddr").val();
			obj.zipCode = $("#txtZipCode").val();
			obj.userSex = $("#cmbSex").val(); // 1: 남자, 2: 여자
			
			return obj;
		}
		
		function _finalize() {
		}
		
		return {
            init : _init,
            finalize : _finalize
        };
    };
    
    var register = new Register();
    register.init();
    
})();

//# sourceURL=register.js