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"); 



중복검사 실행 화면

중복검사

중복검사2

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에 적용

  1. 인코딩 변경 구문 주석처리
    주석처리

  2. 입력된 id를 콘솔에 출력하는 코드 작성
    콘솔출력구문

  3. 로그인 실행 후 콘솔창에 출력되는 화면
    로그인창

    콘솔창 출력

암호화 용 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;
	}	
}



암호화 후 실행 화면

  1. sqlDeveloper의 아이디, 비밀번호
    admin 아이디

  2. 1234로 로그인 시도 / 실패
    로그인 로그인실패

  3. eclipse 콘솔 출력
    콘솔출력창

  4. sqlDeveloper의 비밀번호 변경
    디벨로퍼 값 변경

  5. 다시 1234로 로그인 시도 / 성공
    로그인 로그인 성공

콘솔 출력 창 주석처리하기

실제 개발에서는 콘솔에 비밀번호 암호화 전,후 출력되면 안된다.

//		System.out.println("암호화 전 : " + pwd);
//		System.out.println("암호화 후 : " + encPwd);





태그: , , ,

카테고리:

업데이트:

댓글남기기