2020년 12월 29일
업데이트:
아이디 중복검사
중복 검사 수행
idDupCheck.jsp
<!-- 실질적인 중복 검사 수행 (회원가입에 작성한 id를 가지고 db로 가서 결과를 가지고 옴) -->
<form action="${contextPath }/member/idDupCheck.do" id="idChekcForm" method="post">
<input type="text" id="id" name="id">
<input type="submit" value="중복확인">
</form>
중복검사 Servlet
IdDupCheckServlet.java
package com.kh.wsp.member.controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.kh.wsp.member.model.service.MemberService;
@WebServlet("/member/idDupCheck.do")
public class IdDupCheckServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// post 형식으로 데이터를 전달받지만 ID에는 한글이 포함되지 않아
// 인코딩을 변경하지 않아도 글자가 깨지지 않음.
String id = request.getParameter("id");
try {
// 1) 비즈니스 로직을 호출하여 결과 반환 받기
int result = new MemberService().inDupCheck(id);
// 2) 반환 결과를 request에 세팅하여 요청 위임 진행
request.setAttribute("result", result);
// 상대경로 : url의 가장 마지막 주소를 바꿈
RequestDispatcher view = request.getRequestDispatcher("idDupForm.do");
// IdDupFormservlet으로 요청 위임을 진행함.
// IdDupFormservlet이 받아서 IdDupCheck.jsp로 위임함
view.forward(request, response);
}catch(Exception e) {
e.printStackTrace();
String path = "/WEB-INF/views/common/errorPage.jsp";
request.setAttribute("errorMsg", "아이디 중복 검사 과정에서 오류 발생.");
RequestDispatcher view = request.getRequestDispatcher(path);
view.forward(request, response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
위임되는 순서
중복검사 Service
/** 중복검사 Service
* @param id
* @return result
* @throws Exception
*/
public int inDupCheck(String id) throws Exception {
// 1) 커넥션 얻어오기
Connection conn = getConnection();
// 2) DAO 호출 한 후 결과 반환 받기
int result = dao.inDupCheck(conn, id);
// 3) 커넥션 반환
close(conn);
// 4) 결과 반환
return result;
}
중복검사 SQL
<entry key="inDupCheck">
SELECT COUNT(*) FROM MEMBER
WHERE MEMBER_ID=?
AND MEMBER_STATUS = 'Y'
</entry>
중복검사 DAO
/** 중복검사 DAO
* @param conn
* @param id
* @return result
* @throws Exception
*/
public int inDupCheck(Connection conn, String id)throws Exception {
// 결과 저장할 변수 선언
int result =0;
// SQL 구문 준비
String query = prop.getProperty("inDupCheck");
try {
// 3) PreparedStatement 객체를 얻어와 SQL구문을 세팅
pstmt = conn.prepareStatement(query);
// 4) 위치 홀더(?) 에 알맞은 값 세팅
pstmt.setString(1, id);
// 5) SQL 구문 실행 후 반환값 저장
rset = pstmt.executeQuery();
if(rset.next()) {
result = rset.getInt(1);
}
}finally {
// 6) 사용한 JDBC 자원 반환
close(rset);
close(pstmt);
}
return result;
}
사용 가능 여부 메세지 출력
idDupCheck.jsp
반환받은 result 값으로 사용 가능 여부 판단.
<!-- 사용 가능 여부 메세지 출력 -->
<span>
<c:if test="${!empty result }">
<c:choose>
<c:when test="${result == 0 }">사용 가능한 아이디입니다.</c:when>
<c:otherwise>이미 사용중인 아이디입니다.</c:otherwise>
</c:choose>
</c:if>
</span>
전체 idDupCheck.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>아이디 중복 검사</title>
</head>
<style>
body>*{
margin-left: 75px;
}
</style>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<body>
<h4 class="mt-3">아이디 중복 검사</h4>
<br>
<!-- 실질적인 중복 검사 수행 (회원가입에 작성한 id를 가지고 db로 가서 결과를 가지고 옴) -->
<form action="${contextPath }/member/idDupCheck.do" id="idChekcForm" method="post">
<input type="text" id="id" name="id">
<input type="submit" value="중복확인">
</form>
<br>
<!-- 사용 가능 여부 메세지 출력 -->
<span>
<c:if test="${!empty result }">
<c:choose>
<c:when test="${result == 0 }">사용 가능한 아이디입니다.</c:when>
<c:otherwise>이미 사용중인 아이디입니다.</c:otherwise>
</c:choose>
</c:if>
</span>
<br>
<br>
<div>
<input type="button" id="cancel" value="취소" onclick="window.close();">
<input type="button" id="confirmId" value="확인" onclick="confirmId();">
</div>
<script type="text/javascript">
var id;
var result;
// 팝업창이 오픈 완료 된 후 자동으로 실행
$(function(){
result = "${result}";
/*${result} == 중복검사 실행했을 때 중복이 되면 1, 아니면 0 을 반환 받아옴, 처음에는 비어있음 */
console.log(result);
// 팝업창 최초 오픈 시 if문이 동작되고 중복 체크 버튼으로 인한 팝업창 재 요청 시 else문이 실행됨.
if(id == null && result == ""){
id = opener.document.signUpForm.id.value; // 부모창의 아이디 저장
}else{
// 중복 체크 후 아이디 저장
id = "${param.id}";
}
console.log(id);
// 부모창에서 입력한 아이디 또는 중복검사를 진행한 아이디를 화면에 표시
//document.getElementById("id").value = id;
$("#id").val(id);
});
// 확인버튼을 눌렀을 경우 부모창에 전달할 값 제어
function confirmId(){
// 중복체크 결과 중복되는 아이디가 없을 경우(result가 0인 경우)
if(result == 0){
// 부모창 문서 내에서 signUpForm 이라는 이름의 태그 내에 id라는 이름을 가진 태그의 value값을
// 현재 태그 중 id가 "id" 요소의 값을 대입.
opener.document.signUpForm.id.value = $("#id").val();
// 부모창에 type이 hidden인 요소의 값을 true로 변경
opener.document.signUpForm.idDup.value = true;
}else{
// 중복인 상태로 확인을 누른 경우 부모창에 type이 hidden인 요소의 값을 false로 변경
opener.document.singUpCheck.signUpForm.idDupCheck = false;
}
if(opener != null){ // 아이디 중복창 닫기
opener.checkForm = null;
self.close();
}
}
$("#idChekcForm").submit(function(){
var regExp = /^[a-z][a-zA-z\d]{5,11}$/;
if(!regExp.test($("#id").val())){
alert("유효하지 않은 아이디 형식 입니다.");
return false;
}
});
</script>
</body>
</html>
아이디 중복검사 확인
팝업창 중복체크 여부 판단
signUpForm.jsp
<!-- 팝업창 중복체크 여부 판단을 위한 hidden 타입 요소 -->
<input type="hidden" name="idDup" id="idDup" value="false">
<!-- 중복 검사가 진행됐다면 true, 안 됐으면 false -->
validate 함수로 아이디 중복 검사 여부 확인
중복검사 하지 않았을 경우 회원가입 불가.
wsp_member.js
function validate(){
// 아이디 중복 검사 여부 확인
if($("#idDup").val() != "true"){
swal("아이디 중복 검사를 진행해 주세요.");
$("#idDupCheck").focus();
return false;
}
}
아이디 입력창에 값이 변경될 때
hidden 타입의 값을 false로 바꾼다. 아이디 유효성 검사하는 곳에 코드를 추가한다.
// 아이디가 입력되는 경우 hidden 태그의 값을 false로 변경
$("#idDup").val("false");
중복검사 실행 화면
Filter
인코딩용 Filter
package com.kh.wsp.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
// @WebFilter 어노테이션
// - Servlet 3.0 이상부터 사용 가능하다.
// - filterName : 필터 이름을 지정(필터 순서를 지정할 때 사용)
// - urlPatterns : 필터가 적용될 주소(url)을 지정(패턴 사용 가능)
// - /* : /wsp로 시작하는 모든 url
@WebFilter(filterName = "encoding", urlPatterns = "/*")
public class EncodingFilter implements Filter {
public EncodingFilter() {} // 기본 생성자
// filter 생명 주기
// init() - doFilter() - destroy() 순서로 진행됨.
// filter의 내용이 바뀌면 destroy()가 진행된다.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// url 패턴이 일치하는 요청/ 응답에 대해서 동작하는 메소드
// 요청 / 응답 시 문자 인코딩을 모두 UTF-8로 바꾸는 필터 작성
request.setCharacterEncoding("UTF-8"); // 요청 데이터 문자 인코딩 변경
response.setCharacterEncoding("UTF-8"); // 응답 데이터 문자 인코딩 변경
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
public void destroy() {
}
}
filter확인을 위해 LoginServlet에 적용
-
인코딩 변경 구문 주석처리
-
입력된 id를 콘솔에 출력하는 코드 작성
-
로그인 실행 후 콘솔창에 출력되는 화면
암호화 용 Filter
package com.kh.wsp.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import com.kh.wsp.wrapper.EncryptWrapper;
// url이 여러개인 경우 {} 배열의 형태로 작성한다.
@WebFilter(urlPatterns = {"/member/login.do","/member/signUp.do"})
public class EncryptFilter implements Filter {
public EncryptFilter() {}
public void init(FilterConfig fConfig) throws ServletException {
}
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 비밀번호 암호화
// - 입력된 비밀번호는 HttpServletRequest에 Parameter로 전달 됨.
// -> Parameter의 가공이 필요한 경우 Wrapper 클래스가 필요함.
// 1) HttpServletRequest가 필요함, request를 다운캐스팅으로 형변환 해준다.
HttpServletRequest req = (HttpServletRequest)request;
// 2) 암호화 Wrapper 객체 생성
EncryptWrapper encWrapper = new EncryptWrapper(req);
// encWrapper 가 request 가 됨..
chain.doFilter(encWrapper, response);
}
}
파라미터 가공을 위한 Wrapper 클래스
package com.kh.wsp.wrapper;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class EncryptWrapper extends HttpServletRequestWrapper {
/* HttpServletRequestWrapper를 상속 받음
* -> HttpServletRequestWrapper 객체를 가공할 수 있는 객체
* 특징 : 기본 생성자가 존재하지 않아서, 상속된 매개변수 1개 짜리 생성자를 오버라이딩 해야 함.
*
* */
// 생성자
public EncryptWrapper(HttpServletRequest request) {
super(request);
}
// alt + shift + s -> override/implement methods -> ServletRequestWrapper -> getParameter(String)
@Override
public String getParameter(String name) {
String encPwd = null; // 암호화가 적용된 비밀번호를 저장할 변수
switch(name) {
case "memberPwd" : // 로그인 시 비밀번호 name 속성
case "pwd1" : // 회원가입 시 비밀번호 name 속성
encPwd = getSha512(super.getParameter(name)) ; break;// 암호화
// 얻어온 비밀번호(super.getParameter(name))를 암호화(getSha512) 해서 encPwd에 저장한다.
default : encPwd = super.getParameter(name); // 이전 getParameter 값을 유지
}
return encPwd;
}
/** SHA512 해시 함수를 사용한 암호회 메소드 (SHA : 대중적으로 많이 사용하는 암호화 방식/ 숫자에 따라서 암호화 길이가 달라진다.)
* @param pwd
* @return encPwd
*/
public static String getSha512(String pwd) {
String encPwd = null;
// SHA-512 방식의 암호화 객체 저장 변수 선언
MessageDigest md = null;
// MessageDigest : 지정된 알고리즘에 따라 해시함수를 진행하는 객체
// 해시함수: 입력 값을 여러 단계의 연산을 거쳐 일정한 길이의 무작위 값을 만들어내는 함수.
try {
md = MessageDigest.getInstance("SHA-512");
// 지정된 알고리즘(SHA-512)를 이용해 MessageDigest 객체를 생성 후 얻어옴.
}catch(NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 암호화 전 전달받은 문자열(입력받은 비밀번호)를
// 바이트 배열 형식으로 변환
byte[] bytes = pwd.getBytes(Charset.forName("UTF-8"));
// md 객체에 비밀번호 바이트 배열을 전달하여 갱신
md.update(bytes); // 실제 암호화 진행
// java.util.Base64 인코더를 이용해서 암호화된 바이트 배열을 인코딩 후 문자열로 반환
// 암호화 된 것은 매우 긴 숫자로 되어있다. 사람이 확인하기위해 문자열로 반환해 줌
// Base64 - java.util
encPwd = Base64.getEncoder().encodeToString(md.digest());
// md.digest() : 암호화된 결과를 꺼내오는 것
System.out.println("암호화 전 : " + pwd);
System.out.println("암호화 후 : " + encPwd);
return encPwd;
}
}
암호화 후 실행 화면
-
sqlDeveloper의 아이디, 비밀번호
-
1234로 로그인 시도 / 실패
-
eclipse 콘솔 출력
-
sqlDeveloper의 비밀번호 변경
-
다시 1234로 로그인 시도 / 성공
콘솔 출력 창 주석처리하기
실제 개발에서는 콘솔에 비밀번호 암호화 전,후 출력되면 안된다.
// System.out.println("암호화 전 : " + pwd);
// System.out.println("암호화 후 : " + encPwd);
댓글남기기