JSP 공부를 해볼려고 동빈나님 동영상 강의를 보다가 '이 부분은 이렇게 했으면 좋겠다' 싶어서 블로그에 글을 올리게 되었습니다.
마음에 들지 않았던 부분
1강~5강까지 진행하면서 마음에 들지 않았던 부분은 총 3가지 입니다.
- 회원가입 등록버튼을 눌렀을 때 회원가입 양식에 값이 들어가 있지 않으면 servelet에서 새로운 회원가입 창을 redirect 시키므로 사용자가 입력했던 모든 값이 사라진다.
- 아이디 중복확인 버튼이 있지만, 아이디 중복확인을 하지 않고 회원등록 버튼을 누를 수 있다.
- 비밀번호가 서로 다르더라도 회원 등록버튼을 누를 수 있다.
해결방안
해결방안은 공통적으로 JavaScript를 이용하기로 하였습니다.
- submit 전에 return finalCheck(); 를 통해 예외처리를 실행한다.
- <div>태그 안에 hidden값으로 flag를 숨겨놓는다. flag 값에 따라서 중복체크를 했는지 안했는지 판단한다. -> 중복체크를 한 후에 사용자가 아이디값을 바꾼다면 flag값을 초기화 한다.
- submit 전에 비밀번호가 다르면 action이 작동하지 않게한다. (1번과 같음)
코드
1. 먼저 회원가입 양식부분의 form에 onSubmit="return finalCheck();" 를 추가하여 submit 버튼을 눌렀을 때 submit이 되기 전에 finalCheck() 라는 JavaScript를 실행하도록 하였습니다.
<form method="post" action="./userRegister" onSubmit="return finalCheck();">
finalCheck() 부분은 다음과 같습니다. 정규식을 사용하여 패스워드 조건, 이름 조건 등을 추가하였습니다.
만약에 각 양식의 조건에 맞지 않으면 만들어놓은 modal 창에 그 이유를 표시하고 return false를 통해 submit이 되지 않도록 하였습니다.
function finalCheck(){
var idCheck = $('#idCheck').val();
var userPassword1 = $('#userPassword1').val();
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})?)$/;
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;
}
}
2. 다음은 id중복체크 부분입니다. 회원가입 양식의 '아이디' 부분에 'idCheck'라는 hidden값을 추가한 후 중복확인 버튼을 누르면 'idCheck'의 value값이 1로 바뀌도록 구성해보았습니다. 또한 중복체크를 성공한 후에 사용자가 id를 변경할 수도 있으니 'userID'값에 onkeyup을 통해 사용자가 입력을 하는 순간 'idCheck'값을 초기화(0)하도록 하였습니다.
회원가입 양식의 hidden값, onkeyup 추가
<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로 바꿔줍니다.
function registerCheckFuntion(){
var userID = $('#userID').val();
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";
$('#checkModal').modal("show");
return ;
}
$.ajax({
type : 'POST',
url : './UserRegisterCheck',
data: {userID: userID},
success: function(result){
if(result==1){
$('#checkMessage').html('사용할 수 있는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-success');
document.getElementById("idCheck").value="1";
}else{
$('#checkMessage').html('사용할 수 없는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-warning');
}
$('#checkModal').modal("show");
}
});
}
이 부분은 onkeyup을 통해 실행되는 'idCheck'를 초기화해주는 부분입니다.
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>
<script src="js/bootstrap.js"></script>
<script type="text/javascript">
function registerCheckFuntion(){
var userID = $('#userID').val();
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";
$('#checkModal').modal("show");
return ;
}
$.ajax({
type : 'POST',
url : './UserRegisterCheck',
data: {userID: userID},
success: function(result){
if(result==1){
$('#checkMessage').html('사용할 수 있는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-success');
document.getElementById("idCheck").value="1";
}else{
$('#checkMessage').html('사용할 수 없는 아이디입니다.');
$('#checkType').attr('class','modal-content panel-warning');
}
$('#checkModal').modal("show");
}
});
}
function init_idCheck(){
document.getElementById("idCheck").value="0";
}
function passwordCheckFunction(){
var userPassword1 = $('#userPassword1').val();
var userPassword2 = $('#userPassword2').val();
var password_pattern = /^(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9])(?=.*[0-9]).{8,20}$/;
if(!password_pattern.test(userPassword1)){
$('#passwordCheckMessage').html('비밀번호는 알파벳,숫자,특수문자 포함 8-20자 여야합니다.');
return ;
}else{
$('#passwordCheckMessage').html('');
if(userPassword1 != userPassword2){
$('#passwordCheckMessage').html('비밀번호가 서로 일치하지 않습니다.');
}else{
$('#passwordCheckMessage').html('');
}
}
}
function finalCheck(){
var idCheck = $('#idCheck').val();
var userPassword1 = $('#userPassword1').val();
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})?)$/;
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">
<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>
$('#messageModal').modal("show");
</script>
<%
//모달창이 띄워진 후에는 세션을 파괴해서 중복되지 않도록한다. (단 한번만 사용자에게 보여짐)
session.removeAttribute("messageContent");
session.removeAttribute("messageType");
}
%>
<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