카테고리 없음

#60. JSP/Servlet 사진게시판(상세조회), AJAX(아이디중복체크)

열하나요 2023. 9. 25. 12:05

60-1. 사진게시판 상세조회

1. 상세보기 페이지 만들기

thumbnailDetailView.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.ArrayList, com.kh.jsp.board.model.vo.*" %>
<%
	Board b = (Board)request.getAttribute("b");
	ArrayList<Attachment> list = (ArrayList<Attachment>)request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>사진게시판</title>
<style>
    #detail-form{
        border : 1px solid white;
    }
</style>
</head>
<body>

	<%@ include file="../common/menubar.jsp" %>

	<div class="outer">
		<br>
		<h2 align="center">상세보기 페이지</h2>
		<br>
		
			<table align="center" border="1" id="detail-form">
				<tr>
					<th width="150">제목</th>
					<td colspan="3"><%= b.getBoardTitle() %></td>
				</tr>
                <tr>
                    <th>작성자</th>
                    <td><%= b.getBoardWriter() %></td>
                    <td>작성일</td>
                    <td><%= b.getCreateDate() %></td>
                </tr>
				<tr>
					<th>내용</th>
					<td colspan="3">
                        <p style="height:100%;"><%= b.getBoardContent() %></p>
					</td>
				</tr>
				<tr>
					<th>대표이미지</th>
					<td colspan="3" align="center">
						<img src="<%= contextPath %>/<%= list.get(0).getFilePath() %>/<%= list.get(0).getChangeName() %>" alt="대표이미지" id="titleImg" width="250" height="180">
					</td>
				</tr>
				<% for(int i = 1; i < list.size(); i++) { %>
				<tr>
					<th>상세이미지<%= i %></th>
					<td><img src="<%= contextPath %>/<%= list.get(i).getFilePath() %>/<%= list.get(i).getChangeName() %>" alt="상세이미지<%= i %>" id="contentImg<%= i %>" width="150" height="110"></td>
				</tr>
				<% } %>
			</table>
			<br>

			<br>
			<div align="center">
                <a href="<%=contextPath %>/list.th" class="btn btn-sm btn-info">목록으로</a>
			</div>

			<br><br><br>



	</div>    

</body>
</html>

 

 

2. 리스트 목록을 클릭하면 상세보기 페이지로 이동

thumbnailListView.jsp

기존 thumbnail div에 input hidden으로 하나 만들어주고 클릭 시 경로를 보내준다.

<!-- 게시글이 존재할 경우 -->
<% for(Board b : list) { %>
    <div class="thumbnail" align="center">
        <input type="hidden" value="<%= b.getBoardNo() %>">
        <img src="<%= b.getTitleImg() %>">
        <p>
            No. <%= b.getBoardNo() %> / <%= b.getBoardTitle() %> <br>
            조회수 : <%= b.getCount() %>
        </p>
    </div>
    <% } %>
<% } %>

<script>
    $(function(){
        $('.thumbnail').click(function(){

            // 클릭할 때 마다 url요청 => location.href
            const bno = $(this).children().eq(0).val();
            location.href = '<%= contextPath %>/detail.th?bno=' + bno;
        })
    })
</script>

 

 

3. 게시글 번호를 가지고 조회수 증가요청(이미 해놈)과 상세 정보를 요청할 Controller 만들기 

ThumbnailDetailController.java

- 증가요청 UPDATE은 이미 해놓은 것을 사용할 수 있다.

- 상세정보 SELECT는

기존의 메소드를 쓰려고 할 때, 사진게시판은 CATEGORY_NO가 null이라서 조회가 안됨
기존의 selectBoard의 SQL문 INNER JOIN을 OUTER JOIN으로 변경하면
null인 값도 조회되고 기존의 일반게시판 조회에도 문제가 없으니 LEFT (OUTER) JOIN으로 변경한다.

@WebServlet("/detail.th")

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 인코딩??
    // request.setCharacterEncoding("UTF-8");

    // 글번호 뽑아오기
    int boardNo = Integer.parseInt(request.getParameter("bno"));

    // 가공 ~??

    // 서비스요청
    // 1. 조회수 증가시키는 요청 (이미 해놓은 것을 써먹음)
    int result = new BoardService().increaseCount(boardNo);

    // 2. 1번이 성공했을 경우 => Board에서 조회 요청, Attachment에서도 조회 요청
    if(result > 0) {

        // BOARD테이블 조회 요청
        Board b = new BoardService().selectBoard(boardNo);

        // 기존에 만들어두었던 selectBoard()를 호출해서 재활용하려 했더니 null값이 나옴
        // 일반게시판의 경우 카테고리컬럼에 null인 게시글이 없었지만
        // 사진게시판의 경우 카테고리 컬럼의 값이 전부 null이기 때문에 innerJoin으로는 조회가 불가능
        // => 카테고리 컬럼을 기준으로 일치하는 컬럼, 그렇지 않은 컬럼도 모두 조회하려고 하면
        // 기존의 innerJoin을 outerJoin으로 바꿔주어야 함.

        //System.out.println(b); // null이 떴다가 outer로 바꾸니 안뜸

        // Attachment에서도 조회를 해야 함. 
        ArrayList<Attachment> list = new BoardService().selectAttachmentList(boardNo);

        // 요청 결과를 Attribute영역에 담기
        request.setAttribute("b", b);
        request.setAttribute("list", list);

        // 응답 View지정
        // views/board/thumbnailDetailView.jsp
        request.getRequestDispatcher("views/board/thumbnailDetailView.jsp").forward(request, response);
    }
}

 

4. board-mapper SQL문

 - 기존의 selectBoard SQL문을 outerJoin으로 바꿔 사용

<entry key="selectBoard">
    SELECT 
           BOARD_NO,
           CATEGORY_NAME,
           BOARD_TITLE,
           BOARD_CONTENT,
           USER_ID,
           CREATE_DATE
      FROM
           BOARD
      LEFT
      JOIN 
           CATEGORY USING(CATEGORY_NO)
      JOIN 
           MEMBER ON (BOARD_WRITER = USER_NO)
     WHERE 
           BOARD_NO = ?
       AND 
           BOARD.STATUS = 'Y'
</entry>

 - 기존의 selectAttachment SQL문을 orderby 정렬해서 사용

<entry key="selectAttachment">
    SELECT
           FILE_NO,
           ORIGIN_NAME,
           CHANGE_NAME,
           FILE_PATH
      FROM
           ATTACHMENT
     WHERE 
           REF_BNO = ?
     ORDER
        BY 
           FILE_NO ASC
</entry>

5. BoardService.java

// 사진게시판 게시글 상세조회
// 게시글의 첨부사진들 조회
public ArrayList<Attachment> selectAttachmentList(int boardNo){

    Connection conn = getConnection();

    ArrayList<Attachment> list = new BoardDao().selectAttachmentList(conn, boardNo);

    close(conn);

    return list;
}

 

6. BoardDao.java

// 사진게시판 게시글 상세조회
// 게시글의 첨부사진들 조회
public ArrayList<Attachment> selectAttachmentList(Connection conn, int boardNo){

    ArrayList<Attachment> list = new ArrayList();
    PreparedStatement pstmt = null;
    ResultSet rset = null;
    String sql = prop.getProperty("selectAttachment");

    try {
        pstmt = conn.prepareStatement(sql);
        pstmt.setInt(1, boardNo);
        rset = pstmt.executeQuery();

        while(rset.next()) {
            Attachment at = new Attachment();
            at.setFileNo(rset.getInt("FILE_NO"));
            at.setOriginName(rset.getString("ORIGIN_NAME"));
            at.setChangeName(rset.getString("CHANGE_NAME"));
            at.setFilePath(rset.getString("FILE_PATH"));
            list.add(at);
        }

    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(rset);
        close(pstmt);
    }
    return list;
}

 

 

60-2. AJAX

에이잭스 시작!

Ajax_Project (Dynamic Web Project) 생성

1. WebContent > index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>새로운걸 또 배우는 날(AJAX의 시작)</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js"></script>
</head>
<body>

	<h1>AJAX개요!</h1>
	<p>
		Asynchronous JavaScript And XML의 약자로 <br>
		서버로부터 데이터를 가져와서 전체 페이지를 다시 만들지 않고
		일부만 로드해 내용물만 바꿀 수 있는 기법<br><br>
		
		참고로, 우리가 기존에 a태그를 이용해서 요청 및 form태그를 이용해서 요청한 방식은 동기식 요청! <br>
		=> 응답페이지가 돌아와야 그 결과를 볼 수 있었다.(== 페이지가 한 번 깜빡거린다.) <br><br>
		
		비동기식 요청을 보내기 위해서는 AJAX라는 기술이 필요함 <br><br>
		* 동기식 / 비동기식 요청 차이 <br>
		- 동기식 : 요청 처리 후 해당하는 응답 HTML데이터가 돌아와야만 그 다음 작업이 가능 <br>
				만약 서버에서 응답페이지를 돌려주는 시간이 지연되면 무작정 기다려야 함 <br>
				전체페이지가 리로드됨(새로고침, 페이지가 기본적으로 한 번 깜빡거리면서 넘어감) <br>
				
		- 비동기식 : 현재 페이지는 그대로 유지하면서 중간중간마다 추가적인 요청을 보내줄 수 있음 <br>
				요청을 보낸다고 해서 다른 페이지로 넘어가지 않음(현재 페이지가 그대로 유지) <br>
				요청을 보내놓고 그에 해당하는 응답이 돌아올 때까지 현재 페이지에서 다른 작업을 할 수 있음(페이지가 깜빡이지 않음) <br>
				
		예) NAVER 아이디 중복체크 기능, 댓글, 검색어 자동완성 <br><br>
		
		* 비동기식 단점 <br>
		- 페이지 내 복잡도가 기하급수적으로 증가 => 에러 발생 시 디버깅이 어려움 <br>
		- 요청 후 돌아온 응답데이터를 가지고 현재 페이지에서 새로운 요소를 동적으로 만들어서 뿌려줘야 함<br>
		=> DOM요소를 새롭게 만들어내는 구문을 잘 익혀둬야 함 <br><br>
		
		* AJAX구현방식 : JavaScript방식 / jQuery방식 <br>
		=> jQuery가 코드가 간결하고 사용하가ㅣ 쉬움 <br><br>
	</p>
	
	<pre>
	
		* jQuery에서의 AJAX통신
		
		[ 표현법 ]
		$.ajax({
			속성명 : 속성값,
			속성명 : 속성값,
			속성명 : 속성값,
			...
		});
		
		* 주요속성
		- url : 요청할 url(필수로작성) => form태그의 action속성
		- type : 요청 전송방식(GET/POST 등등... 생략 시 기본값은 get) => form태그의 method속성
		- data : 요청 시 전달할 값({키:밸류, 키:밸류...}) => form태그의 input태그에 입력한 값
		- success : AJAX통신 성공 시 실행할 익명함수를 정의
		
		- error : AJAX통신 실패 시 실행할 익명함수를 정의 
		- complete : AJAX통신을 성공하든 실패하든 무조건 끝나면 실행할 익명함수를 정의
		- async : 서버와의 비동기 처리방식 설정 여부(기본값 true)
		
		
		* 부수적인 속성
	
	
	
	
	
	</pre>
	
	<hr>
	
	<h1>jQuery방식을 이용한 AJAX테스트</h1>
	
	<h3>1. 버튼 클릭 시 get방식으로 서버에 데이터 전송 및 응답</h3>
	
	입력 : <input type="test" id="input1">
	<button id="btn1">요청해줘~~~</button>
	<br>
	
	응답 : <label id="output1">현재 응답 없음</label>
	
	<script>
		$(function(){
			
			
			$('#btn1').click(function(){
				
				// 동기식 요청 : location.href = '요청url?쿼리스트링';
				
				// 비동기식 요청
				$.ajax({
					url : 'jqAjax1.do',
					// 동기식이었으면? 404떴지
					// 비동기식 => 변화가 없음
					data : {input : $('#input1').val()},
					type : 'get',
					success : function(result){
						console.log('AJAX통신성공!');
						console.log(result);
						$('#output1').text(result);
					},
					error : function(e){
						console.log(e);
						alert('AJAX통신 실패!');
					},
					complete : function(){
						console.log("asdfasdf");
					}
					
				});
				
			});
		})
	
	</script>
	
	<br>
	
	<h3>2. 버튼 클릭 시 POST방식으로 서버에 데이터 전송 및 응답</h3>
	
	이름 : <input type="text" id="input2_1"><br>
	나이 : <input type="number" id="input2_2"><br>
	<button onclick="ajaxTest2();">요청~</button>
	
	<br>
	응답 : <label id="output2">현재 응답 없음</label>
	
	<script>
		function ajaxTest2(){
			
			$.ajax({
				url : 'jqAjax2.do',
				data : {
					name : $('#input2_1').val(),
					age : $('#input2_2').val()
				},
				type : 'post',
				success : function(result){
					console.log(result);
					
					// 배열형태로 넘겼을 때 데이터를 가공해서 눈에 보여지게 하는것은 View의 역할
					// $('#output2').text('이름 : ' + result[0] + ', 나이 : ' + result[1]);
					
					// 자바스크립트에서 객체가 가지고 있는 속성값에 접근하는 방법
					// 객체명.속성명, 객체명['속성명']
					$('#output2').text('이름 : ' + result.name + ', 나이 : ' + result['age']);
				},
				error : function(){
					alert('AJAX통신 실패~');
				}
			})
		}
	</script>
	
	<hr>
	
	<h3>3. 서버로 데이터 전송 후, 조회된 객체를 응답데이터로 받기</h3>
	
	회원 번호 입력 : <input type="text" id="input3">
	<button onclick="test3();">조회</button>
	
	<div id="output3"></div>
	
	<div>---- ArrayList ----</div>
	
	<table id="output4">
		<thead>
			<tr>
				<th>번호</th>
				<th>이름</th>
				<th>나이</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				
			</tr>
		</tbody>
	
	</table>
	
	<script>
		function test3(){
			
			$.ajax({
				url : 'jqAjax3.do',
				data : {num : $('#input3').val()},
				success : function(result){
					console.log(result);
					
					/*
					// VO객체 하나만 넘어온 케이스
					const resultStr = '회원번호 : ' + result.memberNo + '<br>'
								 	+ '회원이름 : ' + result.memberName + '<br>'
								 	+ '나이 : ' + result.age + '<br>';
					$('#output3').html(resultStr);
					*/
					
					
					
					
					
				},
				error : function(){
					console.log('AJAX통신실패!');
				}
			})
			
			
		}
	
	</script>
	br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

</body>
</html>

 

2. AjaxController1.java

mapping값 "/jqAjax1.do"

GET방식

@WebServlet("/jqAjax1.do")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 동기식이었으면?? 빈화면이 나왔겠지
    // System.out.println("Hi");

    // GET방식 => 인코딩X

    // 값 뽑기
    // request.getParameter();
    String str = request.getParameter("input");

    // System.out.println("요청 시 전달값 : " + str);

    String responseData = "입력한 값 : " + str + ", 길이 : " + str.length();

    // 응답

    // 1) 응답데이터에 한글이 있을 경우를 대비해서
    // ** 항상 응답데이터에 대해서 인코딩 설정
    response.setContentType("text/html; charset=UTF-8");

    // 2) 응답 : response.getWriter()
    // => 스트림연결(Servlet맛보기할때사용함)
    response.getWriter().print(responseData);
}

 

3. AjaxController2.java

mapping값 "/jqAjax2.do"

POST방식

 

JSON 라이브러리

https://code.google.com/archive/p/json-simple/downloads

 

Google Code Archive - Long-term storage for Google Code Project Hosting.

 

code.google.com

@WebServlet("/jqAjax2.do")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // POST => 인코딩
    request.setCharacterEncoding("UTF-8");
    // System.out.println("Bye");

    // 값 뽑기
    String name = request.getParameter("name");
    int age = Integer.parseInt(request.getParameter("age"));

    // VO로 가공 => Service요청

    // 결과에 따른 응답
    /*
    // 한글이 있을 경우를 대비해서 인코딩설정(필수)
    response.setContentType("text/html; charset=UTF-8");

    // 넘기기
    response.getWriter().print(name, age);
    print()는 인자값을 하나만 받을 수 있음
    */

    // 어쩔 수 없다
    // 방법 1) 하나의 데이터로 만들어서 보내기
    // 이름 : XXX, 나이 : XX
    /*
    String responseData = "이름 : " + name + ", 나이 : " + age;
    response.setContentType("html/text; charset=UTF-8");
    response.getWriter().print(responseData);
    */

    // 방법2) AJAX를 이용해서 실제 값을 여러 개 보내고 싶을 때 => 정석
    // => JSON(JavaScript Object Notation)
    // AJAX통신 시 데이터 전송에 이용되는 포맷형식 중 하나
    // 자바스크립트 배열 객체 => [value, value, value...]
    // 자바스크립트 일반 객체 => {key:value, key:value, key:value}

    /*
     * JSON처리 시 사용하는 클래스 종류
     * => 자바에서 기본적으로 제공X(라이브러리가 필요 .jar)
     * 
     * https://code.google.com/archive/p/json-simple/downloads
     * 
     * json-simpe01.1.1jar 다운로드 후 dev로 이동 WEB-INF/lib에 붙여넣기
     * 
     * 1. JSONArray => [값1, 값2] 배열형태로 값을 넘길 수 있음
     * 2. JSONObject => {키1:밸류1, 키2:밸류2} 객체형태로 값을 넘길 수 있음
     */

    /*
    JSONArray jArr = new JSONArray(); // [] 자바스크립트 배열형태가 만들어짐
    // 요소 추가 => add()
    jArr.add(name); // ['홍길동']
    jArr.add(age); // ['홍길동', 14]
    // 어려운 얘기는 나중에 해줄게요~~~~********************************************************

    // 인코딩
    // response.setContentType("text/html; charset=UTF-8");
    // => text/html로 넘기게되면 문자열로 '["홍길동", 14]'이 전달됨 => list.toString()이랑 같네?
    // 응답할 데이터의 컨텐트타입을 json으로 지정
    response.setContentType("application/json; charset=UTF-8");
    // ▶(2) ['홍길동', 14]로 넘어감


    // 보내기
    response.getWriter().print(jArr);
    */

    // JSONObject를 이용해서 넘기기
    JSONObject jObj = new JSONObject(); // {} 자바스크립트 객체 형태가 생성됨
    // 객체에 값 담기 => put()
    jObj.put("name", name); // {name : "홍길동"}
    jObj.put("age", age); // {name : "홍길동", age : 14}

    // 값, 저장소, 타입

    // 기본자료형, 참조자료형
    // 리스트, 셋, 맵
    // 변수, 조건문, 반복문

    response.setContentType("application/json; charset=UTF-8");
    // ▶{name: '홍길동', age: 14}

    response.getWriter().print(jObj);

}

 

4. Member.java VO생성

package com.kh.ajax.model.vo;

public class Member {
	
	private int memberNo;
	private String memberName;
	private int age;
}

 

5. AjaxController3.java

@WebServlet("/jqAjax3.do")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // GET방식

    // request값 뽑기
    int memberNo = Integer.parseInt(request.getParameter("num"));

    // DB로부터 데이터를 조회했다는 가정하에 Member객체에 값을 담기
    Member m = new Member(memberNo, "홍길동", 50); // <- 얘는 DB조회 결과물    이라고 치자.

    // m을 응답
    // 형식, 인코딩지정
    // response.setContentType("text/html; charset=UTF-8");
    // response.getWriter().print(m);
    // 내부적으로 toString()호출 문자열 형태로 값이 넘어감

    // JSON
    // 자바타입객체 => JSON타입 객체로 변환(JSONObject)
    /* 하나 넘기는 거
    JSONObject jObj = new JSONObject();			// {}
    jObj.put("memberNo", m.getMemberNo());		// {memberNo : 123}
    jObj.put("memberName", m.getMemberName());	// {memberNo : 123, memberName : "홍길동"}
    jObj.put("age", m.getAge());				// {memberNo : 123, memberName : "홍길동", age : 50}

    // 응답으로 넘기기
    response.setContentType("application/json; charset=UTF-8");
    response.getWriter().print(jObj);

    // ▶{memberNo: 1, memberName: '홍길동', age: 50}
    */

    // 여러 개의 VO가 들어있는 ArrayList를 넘기기
    // ArrayList<Member>
    ArrayList<Member> list = new ArrayList();
    list.add(new Member(1, "홍길동", 50));
    list.add(new Member(2, "고길동", 40));
    list.add(new Member(3, "김길동", 30));

    // System.out.println(list);
    /*
    JSONArray jArr = new JSONArray();

    for(Member member : list) {
        JSONObject jObj = new JSONObject();
        jObj.put("memberNo", member.getMemberNo());
        jObj.put("memberName", member.getMemberName());
        jObj.put("age", member.getAge());

        jArr.add(jObj);
    }

    response.setContentType("application/json; charset=UTF-8");
    response.getWriter().print(jArr);
    // ▶(3) [{…}, {…}, {…}]
    */

    // GSON을 이용한 다른 방법~

    // GSON : Google JSON 라이브러리

    // 형식, 인코딩 지정
    response.setContentType("application/json; charset=UTF-8");

    // Gson 객체 생성
    // Gson gson = new Gson();
    // Gson gson = new Gson();

    // gson.toJson() 호출
    // [ 표현법 ] gson.toJson(응답할객체, 응답할스트림);
    // gson.toJson(m, response.getWriter());
    // => response.getWriter()라는 스트림으로 m이라는 객체를 응답하겠다~

    // 자동으로 키값이 전달하는 객체의 필드명이 됨!

    // VO 객체 하나만 응답 시 JSONObject{} 형태로 만들어서 응답
    // List응답 시 JSONArray{} 형태로 만들어서 응답

    // Gson객체 생성 응답 보내기
    new Gson().toJson(list, response.getWriter());
    // => list라는 객체를 response.getWriter()라는 통로로 응답하겠다.

}

 

60-3. 회원가입 - ID중복체크

1. memberEnrollFrom.jsp

중복확인 버튼 클릭하면!

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
	.outer{
		background-color : palegreen;
		width : 1000px;
		margin : auto;
		color : forestgreen;
		margin-top : 5px;
	}

	#enroll-form input{margin : 5px;}

</style>
<title>가입을 해라</title>
</head>
<body>

	<%@ include file="../common/menubar.jsp" %>
	<!--  ../ : 상위폴더로 이동(view폴더로 이동) -->
	
	<div class="outer">
		<br>
		<h2 align="center">회원가입</h2>
		
		<!-- localhost:8001 -->
		<!-- 아이디, 비밀번호, 이름, 전화번호, 이메일, 주소, 취미 -->
		<!-- include는 내 하위 폴더에 있는 모든 jsp나 html에 있는 변수들을 쓸 수 있음. => Path경로/매핑값 -->
		<form id="enroll-form" action="<%= contextPath %>/insert.me" method="post">
			<table align="center">
				<tr>
					<td>* 아이디</td>
					<td><input type="text" name="userId" maxlength="12" required></td>
					<td><button type="button" onclick="idCheck();">중복확인</button></td>
					<!-- 중복확인 나중에 AJAX배우고 다음주 수요일..? 금요일쯤..? -->
				</tr>
				<tr>
					<td>* 비밀번호</td>
					<td><input type="password" name="userPwd" maxlength="15" required></td>
					<td></td>
				</tr>
				<tr>
					<td>* 비밀번호 확인</td>
					<td><input type="password" maxlength="15" required></td>
					<td></td>
				</tr>
				<tr>
					<td>* 이름</td>
					<td><input type="text" name="userName" maxlength="5" required></td>
					<td></td>
				</tr>
				<tr>
					<td>&nbsp;&nbsp;전화번호</td>
					<td><input type="text" name="phone" placeholder="-를 포함해서 입력해 주세요."></td>
					<td></td>
				</tr>
				<tr>
					<td>&nbsp;&nbsp;이메일</td>
					<td><input type="text" name="email"></td>
					<td></td>
				</tr>
				<tr>
					<td>&nbsp;&nbsp;주소</td>
					<td><input type="text" name="address"></td>
					<td></td>
				</tr>
				<tr>
					<td>&nbsp;&nbsp;취미</td>
					<td colspan="2">
						<input type="checkbox" name="interest" id="sick" value="아프기"><label for="sick">아프기</label>
						<input type="checkbox" name="interest" id="recipe" value="레시피"><label for="recipe">레시피</label>
						<input type="checkbox" name="interest" id="travel" value="여행"><label for="travel">여행</label>

						<br>

						<input type="checkbox" name="interest" id="meet" value="소개팅"><label for="meet">소개팅</label>
						<input type="checkbox" name="interest" id="tea" value="다도"><label for="tea">다도</label>
						<input type="checkbox" name="interest" id="java" value="자바"><label for="java">자바</label>
					</td>
				</tr>
			</table>

			<br><br>

			<div align="center">
				<button type="reset">취소</button>
				<button type="submit" disabled>회원가입</button>
			</div>


		</form>

		
	</div>
	
	<script>
		function idCheck(){
			
			// 아이디 인풋태그에 적은 값이 필요함 => 인풋 요소 자체를 먼저 접근!
			
			// console.log($('#enroll-form input[name=userId]'));
			const $userId = $('#enroll-form input[name=userId]');
			// name이 userId인 요소가 menubar.jsp에도 있기 때문에 조금 더 디테일하게 선택하는 것이 중요함
			
			// AJAX컨트롤러로 요청하기
			
			$.ajax({
				url : 'idCheck.me',
				data : {checkId : $userId.val()},
				// success : result => {
				success : function(result){
					// console.log(result);
					// result 경우의 수 : "NNNNN" / "NNNNY"
					
					if(result == 'NNNNN'){ // 중복된 아이디 == 사용불가
						alert('이미 존재하거나 탈퇴한 회원의 아이디입니다.');
						
						$userId.val('').focus();
					}
					else{ // 중복 X == 사용가능
						
						// 알림창 => confirm();
						if(confirm('사용가능한 아이디입니다. 사용하시겠습니까?')){
							
							// 아이디값은 이후에 변경 불가능하도록 ==> readonly
							$userId.attr('readonly', true);
							
							// 중복확인 전에 막아두었던 submit버튼을 활성화!
							$('#enroll-form button[type=submit]').removeAttr('disabled');
						}
					}
				},
				error : function(){
					console.log('아이디 중복체크 AJAX통신 실패!');
				}
			})
		}
	</script>
	
</body>
</html>

 

2. AjaxIdCheckController.java(Servlet)

@WebServlet("/idCheck.me")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // GET

    // 2) request로부터 값 뽑기
    String checkId = request.getParameter("checkId");

    // 3) VO가공 => 패스~

    // 4) Service 요청
    int count = new MemberService().idCheck(checkId);

    // 5) 결과에 따른 응답~
    response.setContentType("text.html; charset-UTF-8");


    // AJAX는 데이터만 돌려준다~~ => response.getWriter().print()
    // 중복값이 있을 때 count == 1 => 'NNNNN'
    // 중복값이 없을 때 count == 0 => 'NNNNY'
    if(count > 0) {
        response.getWriter().print("NNNNN");
    } else {
        response.getWriter().print("NNNNY");
    }
}

 

3. MemberService.java

하나의 메소드는 하나의 기능만 수행해야 한다~

나중에 유지보수하기 힘듦.

public int idCheck (String checkId) {

    Connection conn = JDBCTemplate.getConnection();

    int count = new MemberDao().idCheck(conn, checkId);

    JDBCTemplate.close(conn);

    return count;
}

 

4. MemberDao.java

public int idCheck(Connection conn, String checkId) {

    int count = 0;
    PreparedStatement pstmt = null;
    ResultSet rset = null;
    String sql = prop.getProperty("idCheck");

    try {
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, checkId);
        rset = pstmt.executeQuery();
        if(rset.next()) {
            count = rset.getInt("COUNT(*)");
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        JDBCTemplate.close(rset);
        JDBCTemplate.close(pstmt);
    }
    return count;
}

 

5. member-mapping.xml

SQL문

<entry key="idCheck">
    SELECT COUNT(*)
      FROM MEMBER
     WHERE USER_ID = ?
</entry>