JSP 공부를 해볼려고 동빈나님 동영상 강의를 보다가 '이 부분은 이렇게 했으면 좋겠다' 싶어서 블로그에 글을 올리게 되었습니다.
마음에 들지 않았던 부분
1강~5강까지 진행하면서 마음에 들지 않았던 부분은 총 3가지 입니다.
- 회원가입 등록버튼을 눌렀을 때 회원가입 양식에 값이 들어가 있지 않으면 servelet에서 새로운 회원가입 창을 redirect 시키므로 사용자가 입력했던 모든 값이 사라진다.
- 아이디 중복확인 버튼이 있지만, 아이디 중복확인을 하지 않고 회원등록 버튼을 누를 수 있다.
- 비밀번호가 서로 다르더라도 회원 등록버튼을 누를 수 있다.
해결방안
- submit 전에 return finalCheck(); 를 통해 예외처리를 실행한다.
- <div>태그 안에 hidden값으로 flag를 숨겨놓는다. flag 값에 따라서 중복체크를 했는지 안했는지 판단한다. -> 중복체크를 한 후에 사용자가 아이디값을 바꾼다면 flag값을 초기화 한다.
- submit 전에 비밀번호가 다르면 action이 작동하지 않게한다. (1번과 같음)
코드
<form method="post" action="./userRegister" onSubmit="return finalCheck();">
//submit전에 모든 예외처리를 확인하는 함수
function finalCheck(){
var idCheck = $('#idCheck').val(); //ID중복체크 여부
var userPassword1 = $('#userPassword1').val(); //Password 같은지 여부
var userPassword2 = $('#userPassword2').val();
var userName = $('#userName').val(); //사용자 이름
var userEmail = $('#userEmail').val(); //사용자 이메일
var password_pattern = /^(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9])(?=.*[0-9]).{8,20}$/; //비밀번호 조건
var blank_pattern = /[\s]/g; //공백인 것들 정규식
var email_pattern = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/;
//ID 중복체크를 하였는지 검사
if(idCheck!="1"){
$('#checkMessage').html('아이디 중복확인을 해주세요');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
if(userPassword1 != userPassword2 || !(password_pattern.test(userPassword1))){
$('#checkMessage').html('비밀번호를 확인해주세요');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
if(!userName || blank_pattern.test(userName)){
$('#checkMessage').html('이름에 공백을 포함되어 있거나, 입력하지 않았습니다.');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
if(!email_pattern.test(userEmail)){
$('#checkMessage').html('이메일 형식에 맞게 입력해주세요.');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
}
<h5>아이디</h5>
<input onkeyup="init_idCheck();" class="form-control" type="text" id="userID" name="userID" maxlength="20" placeholder="20자 이하의 숫자, 알파벳">
<button class="btn btn-primary" onclick="registerCheckFuntion();" type="button">중복체크</button>
<input type="hidden" name="idCheck" id="idCheck" value="0">
실제로 'idCheck'값을 변경하는 부분입니다. ajax를 통해서 ID사용가능 여부를 받아오고, 사용가능하면 'idCheck' value를 1로 바꿔줍니다.
//ID중복확인하는 함수
function registerCheckFuntion(){
var userID = $('#userID').val(); //사용자가 input태그에 넣은 값중 id가 userID인 것을 가져온다.
//ID예외처리
//20자 이하, 숫자, 알파벳만 포함가능 (공백도 같이 걸러진다.)
var userID_pattern=/^[a-zA-Z0-9]{1,20}$/;
if(!userID_pattern.test(userID)){
$('#checkMessage').html('아이디는 숫자와 알파벳 포함, 1~20자 이내여야 사용할 수 있습니다.');
$('#checkType').attr('class','modal-content panel-warning');
document.getElementById("idCheck").value="0"; //중복확인을 하지 않았다는 flag
$('#checkModal').modal("show");
return ;
}
$.ajax({
type : 'POST',
url : './UserRegisterCheck',
data: {userID: userID}, //{parameterName, data} 형식
success: function(result){
if(result==1){
$('#checkMessage').html('사용할 수 있는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-success');
document.getElementById("idCheck").value="1"; //중복확인을 했다는 flag
}else{
$('#checkMessage').html('사용할 수 없는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-warning');
}
$('#checkModal').modal("show");
}
});
}
이 부분은 onkeyup을 통해 실행되는 'idCheck'를 초기화해주는 부분입니다.
//idCheck flag를 초기화 해주는 함수
function init_idCheck(){
document.getElementById("idCheck").value="0";
}
3가지를 모두 예외처리 해보았는데요. 여기까지 join.jsp 전체코드 입니다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/custom.css">
<title>실시간 채팅 서비스</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <!--Ajax를 위해서 공식사이트 에서 제공하는 jquery를 가져온다. -->
<script src="js/bootstrap.js"></script>
<script type="text/javascript">
//ID중복확인하는 함수
function registerCheckFuntion(){
var userID = $('#userID').val(); //사용자가 input태그에 넣은 값중 id가 userID인 것을 가져온다.
//ID예외처리
//20자 이하, 숫자, 알파벳만 포함가능 (공백도 같이 걸러진다.)
var userID_pattern=/^[a-zA-Z0-9]{1,20}$/;
if(!userID_pattern.test(userID)){
$('#checkMessage').html('아이디는 숫자와 알파벳 포함, 1~20자 이내여야 사용할 수 있습니다.');
$('#checkType').attr('class','modal-content panel-warning');
document.getElementById("idCheck").value="0"; //중복확인을 하지 않았다는 flag
$('#checkModal').modal("show");
return ;
}
$.ajax({
type : 'POST',
url : './UserRegisterCheck',
data: {userID: userID}, //{parameterName, data} 형식
success: function(result){
if(result==1){
$('#checkMessage').html('사용할 수 있는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-success');
document.getElementById("idCheck").value="1"; //중복확인을 했다는 flag
}else{
$('#checkMessage').html('사용할 수 없는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-warning');
//document.getElementById("idCheck").value="0"; //중복확인을 하지 않았다는 flag
}
$('#checkModal').modal("show");
}
});
}
//idCheck flag를 초기화 해주는 함수
function init_idCheck(){
document.getElementById("idCheck").value="0";
}
//password가 서로같은지, 조건에 맞는지 확인하여 passwordCheckMessage에 에러 메시지 출력
function passwordCheckFunction(){
var userPassword1 = $('#userPassword1').val();
var userPassword2 = $('#userPassword2').val();
var password_pattern = /^(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9])(?=.*[0-9]).{8,20}$/;
//password 조건 확인
if(!password_pattern.test(userPassword1)){
$('#passwordCheckMessage').html('비밀번호는 알파벳,숫자,특수문자 포함 8-20자 여야합니다.');
return ;
}else{
$('#passwordCheckMessage').html('');
//password서로 일치하는지 확인
if(userPassword1 != userPassword2){
$('#passwordCheckMessage').html('비밀번호가 서로 일치하지 않습니다.');
}else{
$('#passwordCheckMessage').html('');
}
}
}
//submit전에 모든 예외처리를 확인하는 함수
function finalCheck(){
var idCheck = $('#idCheck').val(); //ID중복체크 여부
var userPassword1 = $('#userPassword1').val(); //Password 같은지 여부
var userPassword2 = $('#userPassword2').val();
var userName = $('#userName').val(); //사용자 이름
var userEmail = $('#userEmail').val(); //사용자 이메일
var password_pattern = /^(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9])(?=.*[0-9]).{8,20}$/; //비밀번호 조건
var blank_pattern = /[\s]/g; //공백인 것들 정규식
var email_pattern = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/;
//ID 중복체크를 하였는지 검사
if(idCheck!="1"){
$('#checkMessage').html('아이디 중복확인을 해주세요');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
if(userPassword1 != userPassword2 || !(password_pattern.test(userPassword1))){
$('#checkMessage').html('비밀번호를 확인해주세요');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
if(!userName || blank_pattern.test(userName)){
$('#checkMessage').html('이름에 공백을 포함되어 있거나, 입력하지 않았습니다.');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
if(!email_pattern.test(userEmail)){
$('#checkMessage').html('이메일 형식에 맞게 입력해주세요.');
$('#checkType').attr('class','modal-content panel-warning');
$('#checkModal').modal("show");
return false;
}
}
</script>
</head>
<body>
<%
//SESSION 작업
String userID = null;
if(session.getAttribute("userID") != null){
userID = (String)session.getAttribute("userID");
}
%>
<nav class="navbar navbar-default">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<!--햄버거 메뉴바(오른쪽)를 위해 3개(하나를 없애보면 뭔지 알수있음)-->
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!--옆에(왼쪽) 로고 또는 사이트 이름이 표시되게-->
<a class="navbar-brand" href="index.jsp">실시간 채팅 서비스</a>
</div>
<div class="collapse navbar" id="bs-example-navbar-collapse-1"></div>
<ul class="nav navbar-nav">
<li class="active"><a href="index.jsp">메인</a>
</ul>
<%
if(userID==null){
%>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">접속하기<span class="caret"></span>
</a>
<ul class ="dropdown-menu">
<li><a href="login.jsp">로그인</a></li>
<li><a href="join.jsp">회원가입</a></li>
</ul>
</li>
</ul>
<%
}else {
%>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">회원관리<span class="caret"></span>
</a>
</li>
</ul>
<%
}
%>
</nav>
<!-- 회원가입 양식 -->
<div class="container">
<form method="post" action="./userRegister" onSubmit="return finalCheck();">
<table class="table table-bordered table-hover" style="text-align: center; border: 1px solid #dddddd">
<thead>
<tr>
<th colspan="3"><h4>회원가입</h4></th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 110px;"><h5>아이디</h5></td>
<td><input onkeyup="init_idCheck();" class="form-control" type="text" id="userID" name="userID" maxlength="20" placeholder="20자 이하의 숫자, 알파벳"></td>
<td style="width: 110px;"><button class="btn btn-primary" onclick="registerCheckFuntion();" type="button">중복체크</button>
<input type="hidden" name="idCheck" id="idCheck" value="0"/></td>
</tr>
<tr>
<td style="width: 110px;"><h5>비밀번호</h5></td>
<td colspan="2"><input onkeyup="passwordCheckFunction();" class="form-control" type="password" id="userPassword1" name="userPassword1" maxlength="20" placeholder="알파벳,숫자,특수문자 포함 8-20자"></td>
</tr>
<tr>
<td style="width: 110px;"><h5>비밀번호 확인</h5></td>
<td colspan="2"><input onkeyup="passwordCheckFunction();" class="form-control" type="password" id="userPassword2" name="userPassword2" maxlength="20" placeholder="비밀번호 확인을 입력해주세요"></td>
</tr>
<tr>
<td style="width: 110px;"><h5>이름</h5></td>
<td colspan="2"><input class="form-control" type="text" id="userName" name="userName" maxlength="20" placeholder="이름을 입력해주세요"></td>
</tr>
<tr>
<td style="width: 110px;"><h5>나이</h5></td>
<td colspan="2"><input class="form-control" type="number" id="userAge" name="userAge" maxlength="20" placeholder="나이를 입력해주세요"></td>
</tr>
<tr>
<td style="width: 110px;"><h5>성별</h5></td>
<td colspan="2">
<div class="form-group" style="text-align: center; margin:0 auto;">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary active">
<input type="radio" name="userGender" autocomplete="off" value="남자" checked>남자
</label>
<label class="btn btn-primary">
<input type="radio" name="userGender" autocomplete="off" value="여자">여자
</label>
</div>
</div>
</td>
</tr>
<tr>
<td style="width: 110px;"><h5>이메일</h5></td>
<td colspan="2"><input class="form-control" type="email" id="userEmail" name="userEmail" maxlength="20" placeholder="이메일을 입력해주세요"></td>
</tr>
<tr>
<td style="text-align: left;" colspan="3"><h5 style="color: red;" id="passwordCheckMessage"></h5><input class="btn btn-primary pull-right" type="submit" value="등록"></td>
</tr>
</tbody>
</table>
</form>
</div>
<!-- 회원가입 결과에 따라 성공메시지, 오류메시지 모달창을 띄우는 부분 -->
<%
String messageContent = null;
if(session.getAttribute("messageContent") != null){
messageContent = (String)session.getAttribute("messageContent");
}
String messageType = null;
if(session.getAttribute("messageType") != null){
messageType = (String)session.getAttribute("messageType");
}
if(messageContent != null){
%>
<div class="modal fade" id="messageModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="vertical-alignment-helper">
<div class="modal-dialog vertical-align-center">
<div class="modal-content <% if(messageType.equals("오류메시지")) out.println("panel-warning"); else out.println("panel-success"); %>">
<div class="modal-header panel-heading">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">
<%= messageType %>
</h4>
</div>
<div class="modal-body">
<%= messageContent %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">확인</button>
</div>
</div>
</div>
</div>
</div>
<script>
//위의 div의 id="messageModal"를 실행시키는 스크립트
$('#messageModal').modal("show");
</script>
<%
//모달창이 띄워진 후에는 세션을 파괴해서 중복되지 않도록한다. (단 한번만 사용자에게 보여짐)
session.removeAttribute("messageContent");
session.removeAttribute("messageType");
}
%>
<!-- head부분의 javaScript에서 실행되고, 아이디 사용 유무의 결과를 보여준다. -->
<div class="modal fade" id="checkModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="vertical-alignment-helper">
<div class="modal-dialog vertical-align-center">
<div id="checkType" class="modal-content panel-info">
<div class="modal-header panel-heading">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">
확인 메시지
</h4>
</div>
<div id="checkMessage" class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">확인</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
원본 동영상 : https://youtu.be/bETgFGtnpzQ