JSP에서 실시간으로 통신을 사용할 때 소켓을 이용하게 된다.


미리 구현이 되어 있기 때문에 선언만 하고 메소드를 사용하게 된다.


기본 형태는 JSP에서 Jquery 형식으로 스크립트에 작성하게 된다.


JSP 스크립트 < - > 서블릿과 유사한 ServerEndPoint로


맵핑된 주소로 실시간으로 통신을 하게된다.





기본형태




// 먼저 페이지 시작 시 바로 getConnection 함수를 호출해 Server와 연결한다고 선언


$(function(){
     getConnection();

})



// getConnection이 호출 될 때 연결을 위해 사용하는 메소드들


function getConnection(){
     ws = new WebSocket("ws://localhost:8001" + '<%=request.getContextPath()%>/serverStart');


     // 서버 시작할 때 동작
     ws.onopen = function(event){

     }


     // 서버로부터 메세지를 전달 받을 때 동작하는 메소드

     // 아래에 선언 할 onMessage로 event가 전달된다.

     ws.onmessage = function(event){
           onMessage(event);
     }
               
     // 서버에서 에러가 발생할 경우 동작할 메소드
     ws.onerror = function(event){
          onError(event);
     }
               
     // 서버와의 연결이 종료될 경우 동작하는 메소드
     ws.onclose = function(event){
          onClose(event);
     }
}
           
           


// 전달할 String형 msg를 ws.send를 통해서 소켓으로 전달한다.

function send(msg){
     ws.send(msg);
}




// 서버에서 메시지를 전달 받을 때 event 매개변수로 값을 받고

// 이 메소드에서 event 값을 통해 무엇을 할 것인지 정한다.

function onMessage(event){


     // String 형태로 데이터가 넘어오므로 구분자를 통해서 사용하면 된다.


     // 구분을 "메세지:구분:아이디"와 같다고 할 때

     // 만약 event값이 "메세지내용:msg:3"과 같이 전달 되었다면

     // ":"를 split 메소드를 이용하여 분리하면 담긴 변수에는


     // serverMessage[0] = "메세지내용"

     // serverMessage[1] = "msg"

     // serverMessage[2] = "3"


     // 위와 같이 분리된다.


     // 아래의 예처럼 if문을 이용해서 잘 쓰면 된다.


     var serverMessage = event.data.split(":");


     if(serverMessage[1] ==  "msg") // msg, 메세지일 때

          alert(serverMessage[2] + "님의 메세지 : " + serverMessage[0]);

     } else if (serverMessage[1] == "alarm") {

          alert("알람이 있습니다."):

     }


    

}



// 소켓통신 에러 발생 시
function onError(event){
     alert(event.data);
}
// 소켓통신이 끝낫을 때
function onClose(event){
     alert(event);
}








body 부분에서는 예를들어 버튼에다가


<button onclick="send("안녕하세요:msg:3")"></button>


위와 같이 버튼이 있고 클릭하면 위에서 선언된 메소드인 send가 실행되어


ws.send()로 소켓을 통해 서버로 메세지가 전달이 된다.





다음은 서버에서 메세지를 받을때 파일의 예



코드를 보면 어노테이션을 통해 @ServerEndpoint("/auctionStart") 를 통해서 맵핑이 이루어져 있고


ws = ~~~~ 하고 위에서 Jquery로 선언한 부분에 주소가 맞으면


이 EndPoint를 통해서 통신을 하게 된다.







package com.kh.auction.websocket;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/auctionStart")
public class AuctionStart {
    private static Set<Session> clients = Collections.synchronizedSet(new HashSet<Session>());

    @OnOpen
    public void onOpen(Session session) {
        //서버 연결한 시점에 동작하는 메소드
       
        //기존 사용자 리스트에 새로 연결 요청이 들어온 사용자를 추가한다
        clients.add(session);
    }

    @OnMessage
    public void onMessage(String msg, Session session) throws IOException {
        //서버로부터 데이터를 전송받을 경우 동작할 메소드
        System.out.println(msg);
       
        //하나의 일 처리를 수행하는동안 사용자의 변경이 일어나면 안된다.
        //즉 NullPointer를 방지하기 위해 동기화 처리를 해준다.
        synchronized(clients) {
            for(Session client : clients) {
                client.getBasicRemote().sendText(msg);
               
            }
        }
    }
   
    @OnError
    public void onError(Throwable e) {
        //데이터를 전달하는 과정에서 에러가 발생할 경우 동작하는 메소드
        e.printStackTrace();
    }
   
    @OnClose
    public void onClose(Session session) {
        //지워주지 않으면 Set에 이미 나간 사용자가 남아있기 때문에 메세지 전송시 에러 난다.
        clients.remove(session);
    }
   
   
   
}















private static Set<Session> clients = Collections.synchronizedSet(new HashSet<Session>());


위의 선언을 통해서 현재 통신 시점의 모든 Session들의 정보를 담는다.


다른 부분은 건들일 일이 없는데 @OnMessage 이쪽 부분만 잘 사용하면 된다.


OnMessage 메소드를 통해서 전달된 String형 메세지가 이쪽으로 전달되고


데이터를 처리 한 후




synchronized(clients) {
            for(Session client : clients) {
                client.getBasicRemote().sendText(msg);
               
            }
}



synchronized 부분에서 아까 담았던 모든 session에게 해당 메세지를 전달한다.


client.getBasicRemote().sendText(msg); 이 부분을 수정하여


client의 값에서 id값과 같은 키값을 뽑아 조건문을 통해서


특정 대상만 구분하여 메세지를 보낼 수 있다.







synchronized 바로 윗 부분에서 msg 데이터를 마음대로 가공해도 되고 Service, Dao를 거쳐서


새로운 msg를 만들어도 된다.








결론



Endpoint 서버와 연결(이 때부터 소켓(ws)는 onMessage(event)를 계속 기다리고 있다.)


- ws.send를 통해 서버에 메세지 전달


- 서버에서 데이터 처리 후 세션에 데이터 전송


- 서버에서 메시지가 도착하면 onMessage(event)로 처리





메세지는 전부 String형으로 잘 컨트롤 해야 한다.


JSP를 만드는데 페이지를 새로고침 하지 않고


페이지의 정보를 바꾸고 싶을때 Ajax를 사용한다.


예를들어 네이버의 실시간 검색순위를 보면 일정 시간마다 리스트가 계속 바뀐다. 새로고침은 하지 않고


또 회원가입 시 아이디 중복체크를 누르면 페이지는 그대로 있고 중복인지 아닌지 메세지가 뜬다.


이러한 기능들은 Ajax를 통해 구현된다.


JSP 문서에서 Jquery 문에 Ajax를 사용하고


Servlet에 데이터를 전달받아서 Servlet에서 데이터를 처리 후


Json을 사용하여 데이터를 포장하여 JSP 문서로 전달하게 된다.


하지만 보안 작업에는 적합하지 않으므로 작업에 따라 적절히 사용하자.



Ajax 장단점


- 장점 -


비동기식 방식으로 웹서버 응답을 기다리지 않고 데이터를 빠르게 처리한다.


예로 실시간 검색순위나 자동 완성이 있다.



- 단점 -


새로고침 하지 않고 계속 사용한다면 리소스가 계속 쌓여 페이지가 느려짐


JQ 오류와 같이 오류를 찾기 힘듦







비 동기식 처리모델 : 페이지가 로딩 될 때 먼저 서버에서 연산작업을 요청하고 계속 로딩한다. 작업에 대한 답은 기다리지 않고 처리된다.


동기식 처리모델 : 페이지가 로딩 될 때 서버의 연산을 모두 기다리고 페이지의 연산 처리가 끝나면 나머지 부분을 로드한다.



사용법으로는 먼저 API 사용에 필요한 라이브러리 파일을 받자


파일은 JSON


GSON 파일이 있다.




- JSON -


www.java2s.com/Code/Jar/j/Downloadjsonsimple11jar.htm


위 링크로 들어가면 다운로드가 바로 보인다.




해당 파일을 lib 폴더에 추가하면 된다.








- GSON -


위 링크로 들어가 Gson을 고르고 다음 캡쳐와 같이 진행






해당 파일을 받아 lib에 추가한다.








이와 같이 라이브러리에 추가가 끝나면 JSON, GSON을 사용하는데 문제가 없을 것이다.


Ajax는 Jsp 파일에서 스크립트 단에서 사용하며


특정 동작이 있을 때 페이지를 변경(새로고침)하지 않고 Servlet에 통신 후 데이터를 받아와 변경






$(function(){ // 페이지 시작 시

$.ajax({

url:"서블릿 맵핑 주소",
data:{보낼 데이터 Key : "보낼 데이터 Value"},
type:"get",
 success: function(data) {
    // success는 서버에서 통신 성공 시 받을 자료를 받는다(data)

    // 통신만 성공해도 success로 넘어간다는 것을 주의하자.
    console.log("서버 전송 성공" + data);
},
error:function(data){ // 데이터 통신에 실패한 것
    console.log("서버 전송 실패");   
},
complete:function(data){
    console.log("무조건 호출되는 함수");
}

});

});




이와같이 Ajax는 Jquery를 이용해 서블릿 통신을 하고 그 결과를 통해서 JQuery를 작성하여 여러가지 기능을 쓸 수 있다.


다음은 서블릿에서 다시 Ajax 구문에 data를 전송하는 부분


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

        List<User> userList = new ArrayList<User>();
       
        User user1 = new User(1, "호이1", "외계");
        User user2 = new User(2, "호이2", "외계");
        User user3 = new User(3, "호이3", "외계");
        User user4 = new User(4, "호이4", "외계");
        User user5 = new User(5, "호이5", "외계");
        User user6 = new User(6, "호이6", "외계");
        User user7 = new User(7, "호이7", "외계");
        User user8 = new User(8, "호이8", "외계");
        User user9 = new User(9, "호이9", "외계");
        User user10 = new User(10, "호이10", "외계");
       
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
        userList.add(user4);
        userList.add(user5);
        userList.add(user6);
        userList.add(user7);
        userList.add(user8);
        userList.add(user9);
        userList.add(user10);
       
        int userIndex = Integer.parseInt(request.getParameter("받은 데이터 Key 값"));
       
        User user = userList.get(userIndex - 1);
       
        // 자바에서 자바 스크립트에 알아먹을 수 있게 객체를 바꿔주는 기능(key, value 형식)이 JSON
        // 라이브러리 json simple이 필요
        JSONObject result = new JSONObject();
       
        // 값을 그냥 전달 할 수 없다. 한글이 있으므로 UTF-8 처리를 해야한다.
        result.put("userNo", user.getUserNo());
        result.put("userName", URLEncoder.encode(user.getUserName(), "UTF-8"));
        result.put("userNation", URLEncoder.encode(user.getUserNation(), "UTF-8"));
       
        response.setContentType("application/json");
       
        PrintWriter out = response.getWriter();
       
        out.print(result.toJSONString());
       
        // <textarea>value</textarea> HTML 형태는 textarea가 key가 된다.
        // <key>value</key> xml형태는 key를 html보다 제한적이지 않고 자유롭게 사용 할 수 있다.
        // {key:value} JSON 형태는 xml html보다 쓰기 쉽고 짧아서 바뀌는 추세이다.
       
       
        out.flush();
        out.close();

}





위와 같이 서블릿에서 따로 데이터를 JSON으로 처리를 해야한다.


처리하고 나서 데이터를 전송하는데 과정이 까다롭기 때문에 Gson이라는 오픈소스를 사용하면 편하다.



    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Map<String, User> userMap = new HashMap<String, User>();
       
        User user1 = new User(1, "호이1", "외계");
        User user2 = new User(2, "호이2", "외계");
        User user3 = new User(3, "호이3", "외계");
        User user4 = new User(4, "호이4", "외계");
        User user5 = new User(5, "호이5", "외계");
        User user6 = new User(6, "호이6", "외계");
        User user7 = new User(7, "호이7", "외계");
        User user8 = new User(8, "호이8", "외계");
        User user9 = new User(9, "호이9", "외계");
        User user10 = new User(10, "호이10", "외계");
       
        userMap.put(user1.getUserName(), user1);
        userMap.put(user2.getUserName(), user2);
        userMap.put(user3.getUserName(), user3);
        userMap.put(user4.getUserName(), user4);
        userMap.put(user5.getUserName(), user5);
        userMap.put(user6.getUserName(), user6);
        userMap.put(user7.getUserName(), user7);
        userMap.put(user8.getUserName(), user8);
        userMap.put(user9.getUserName(), user9);
        userMap.put(user10.getUserName(), user10);
       
       
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        new Gson().toJson(userMap, response.getWriter());

       
    }


위와같이 긴 코드가 3줄로 변하는것을 확인 할 수 있다.












직접 사용해보면 Ajax는 실시간이라기 보다는


개발자가 어떤 버튼, 동작에 상호작용하여 어떤 서버와의 통신이 필요할 때 사용할 작업을 설정하는 것이다.


이와 달리 실시간으로 계속 통신을 하고 싶다면 JSP Socket 통신을 이용하면 된다.


일반 게시판에서 사진을 업로드 할 때 방법을 설명


먼저 JSP 파일


------------------------------------------------------------------------------------------------------------------------------------

출처: https://qdgbjsdnb.tistory.com/ [하위^^]
------------------------------------------------------------------------------------------------------------------------------------

출처: https://qdgbjsdnb.tistory.com/ [하위^^]

------------------------------------------------------------------------------------------------------------------------------------

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
    .outer {
        width:1000px;
        height:650px;
        background:black;
        color:white;
        margin-left:auto;
        margin-right:auto;
        margin-top:50px;
    }
    table {
        border:1px solid white;
    }
    .insertArea {
        width:500px;
        height:450px;
        margin-left:auto;
        margin-right:auto;
    }
    .btnArea {
        width:150px;
        margin-left:auto;
        margin-right:auto;
    }
    #titleImgArea {
        width:350px;
        height:200px;
        border:2px dashed darkgray;
        text-align:center;
        display:table-cell;
        vertical-align:middle;
    }
    #contentImgArea1, #contentImgArea2, #contentImgArea3 {
        width:150px;
        height:100px;
        border:2px dashed darkgray;
        text-align:center;
        display:table-cell;
        vertical-align:middle;
    }
</style>
</head>
<body>
    <%@ include file="../common/menubar.jsp" %>
    <% if(loginUser != null) { %>
    <div class="outer">
        <br>
        <h2 align="center">사진 게시판 작성</h2>
        <form action="<%=request.getContextPath() %>/insert.tn" method="post" encType="multipart/form-data"> <!-- 파일 전송 시 encType을 지정해야 한다. -->
            <div class="insertArea">
                <table align="center">
                    <tr>
                        <td>제목</td>
                        <td colspan="3"><input type="text" size="45" name="title"></td>
                    </tr>
                    <tr>
                        <td>대표 이미지</td>
                        <td colspan="3">
                            <div id="titleImgArea">
                                <img id="titleImg" width="350" height="200">
                            </div>
                        </td>
                    </tr>
                    <tr>
                        <td>내용사진</td>
                        <td>
                            <div id="contentImgArea1">
                                <img id="contentImg1" width="120" height="100">
                            </div>
                        </td>
                        <td>
                            <div id="contentImgArea2">
                                <img id="contentImg2" width="120" height="100">
                            </div>
                        </td>
                        <td>
                            <div id="contentImgArea3">
                                <img id="contentImg3" width="120" height="100">
                            </div>
                        </td>
                    </tr>
                    <tr>
                        <td width="100px">사진 메모</td>
                        <td colspan="3">
                            <textarea name="content" rows="5" cols="50" style="resize:none;"></textarea>
                        </td>
                    </tr>
                </table>
                <div id="fileArea">
                    <input type="file" id="thumbnailImg1" name="thumbnailImg1" onchange="loadImg(this, 1)">
                    <input type="file" id="thumbnailImg2" name="thumbnailImg2" onchange="loadImg(this, 2)">
                    <input type="file" id="thumbnailImg3" name="thumbnailImg3" onchange="loadImg(this, 3)">
                    <input type="file" id="thumbnailImg4" name="thumbnailImg4" onchange="loadImg(this, 4)">
                </div>
            </div>
            <div class="btnArea">
                <button>취소하기</button>
                <button type="submit">작성완료</button>
            </div>
        </form>
    </div>
   
    <script type="text/javascript">
        $(function() {
            $("#fileArea").hide(); // 버튼 숨기기
           
            $("#titleImgArea").click(function() {
                $("#thumbnailImg1").click();
            });
            $("#contentImgArea1").click(function() {
                $("#thumbnailImg2").click();
            });
            $("#contentImgArea2").click(function() {
                $("#thumbnailImg3").click();
            });
            $("#contentImgArea3").click(function() {
                $("#thumbnailImg4").click();
            });
        });
        /* function loadImg(value) { // 박스에 파일 업로드 하는 방법
            if (value.files && value.files[0]) {
                var reader = new FileReader();
               
                reader.onload = function(e) {
                    $("#titleImg").attr("src", e.target.result);
                };
               
                reader.readAsDataURL(value.files[0]);
            }
        } */
        function loadImg(value, num) { // value는 업로드한 파일
            if (value.files && value.files[0]) { // 파일을 업로드하면 배열 형태로 들어온다.
                var reader = new FileReader();
               
                reader.onload = function(e) { // reader가 실행되면 적용될 속성
                    switch (num) {
                    case 1 :
                        $("#titleImg").attr("src", e.target.result); // target.result는 업로드한 파일의 임시경로
                        break;
                    case 2 :
                        $("#contentImg1").attr("src", e.target.result);
                        break;
                    case 3 :
                        $("#contentImg2").attr("src", e.target.result);
                        break;
                    case 4 :
                        $("#contentImg3").attr("src", e.target.result);
                        break;
                    }
                };
               
                reader.readAsDataURL(value.files[0]); // reader호출, 파일의 url을 읽어 들임
            }
        }
    </script>
   
    <% } else { %>
    <%    
        request.setAttribute("msg", "잘못된 경로로 접근하셨습니다.");
        request.getRequestDispatcher("../common/errorPage.jsp").forward(request, response);
    %>
    <% } %>
</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------


다른 폼은 여태껏 봐왔던 html 코드들인데


스크립트 부분을 설명하면


        $(function() {
            $("#fileArea").hide(); // 버튼 숨기기
           
            $("#titleImgArea").click(function() {
                $("#thumbnailImg1").click();
            });
            $("#contentImgArea1").click(function() {
                $("#thumbnailImg2").click();
            });
            $("#contentImgArea2").click(function() {
                $("#thumbnailImg3").click();
            });
            $("#contentImgArea3").click(function() {
                $("#thumbnailImg4").click();
            });
        });


이 부분은 이미지 박스를 눌렀을 때 버튼 기능을 실행하게 하고


버튼은 숨겨 안보이게 표시하는 스크립트




        /* function loadImg(value) { // 박스에 파일 업로드 하는 방법
            if (value.files && value.files[0]) {
                var reader = new FileReader();
               
                reader.onload = function(e) {
                    $("#titleImg").attr("src", e.target.result);
                };
               
                reader.readAsDataURL(value.files[0]);
            }
        } */


type="file"에 함수를 만들어 value를 인자로 받았을 때


value는 받은 파일을 의미하게 된다.


value는 여러개가 들어올 수 있으므로 배열 형태로 들어오게 되고


files 라는 메소드는 파일이 있는지 없는지를 반환한다.




FileReader 객체를 생성하고 불러올 때 작동할 함수(onload)는 클릭한 박스의 속성의 이미지를 등록하는 것이다.


function(e) 의 e는 등록한 파일을 의미하고 e.target.result는 서버에 업로드 하기 전에 임시로 지정된 파일의 경로가 된다.


reader.readAsDataURL(value.files[0])은 파일의 경로를 한번 불러오는 것이고 호출했기 때문에 onload가 작동된다.






        function loadImg(value, num) { // value는 업로드한 파일
            if (value.files && value.files[0]) { // 파일을 업로드하면 배열 형태로 들어온다.
                var reader = new FileReader();
               
                reader.onload = function(e) { // reader가 실행되면 적용될 속성
                    switch (num) {
                    case 1 :
                        $("#titleImg").attr("src", e.target.result); // target.result는 업로드한 파일의 임시경로
                        break;
                    case 2 :
                        $("#contentImg1").attr("src", e.target.result);
                        break;
                    case 3 :
                        $("#contentImg2").attr("src", e.target.result);
                        break;
                    case 4 :
                        $("#contentImg3").attr("src", e.target.result);
                        break;
                    }
                };
               
                reader.readAsDataURL(value.files[0]); // reader호출, 파일의 url을 읽어 들임
            }
        }



2번째 스크립트의 확장으로 이미지 선택 박스의 종류 별 기능을 활성화 한다.








submit으로 설정한 버튼을 통해서


<form action="<%=request.getContextPath() %>/insert.tn" method="post" encType="multipart/form-data"> 부분의


<%=request.getContextPath() %>/insert.tn 주소로 맵핑된 부분으로 이동된다.


이동된 부분은 Servlet 파일로 서버에 업로드 된 파일을 처리한다.


단, 파일을 보낼 때는 form 속성에 무조건 encType="multipart/form-data" 를 명시해야 한다.








다음으로는 Servlet 파일

------------------------------------------------------------------------------------------------------------------------------------

package com.kh.jsp.board.controller;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.util.ArrayList;
import java.util.Enumeration;

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 org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;

import com.kh.jsp.board.model.service.BoardService;
import com.kh.jsp.board.model.vo.Attachment;
import com.kh.jsp.board.model.vo.Board;
import com.kh.jsp.common.MyFileRenamePolicy;
import com.kh.jsp.member.model.vo.Member;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

@WebServlet("/insert.tn")
public class InsertThumbnailServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
      
    public InsertThumbnailServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String title = request.getParameter("title");
        System.out.println(title);
        // encType="multipart/form-data"로 데이터를 넘기면 null이 출력된다.
        // 폼전송을 multipart/form-date로 전송하는 경우에는
        // 기존처럼 request.getParameter로 값을 받을 수 없다.
       
        // cos.jar가 파일도 받고 다른 값들도 받아주는 역할을 한다.
        // com.oreilly.servlet의 약자이다.
        // http://servlets.com/cos/ 맨 아래에서 다운로드해서 lib에 추가한다.
       
        if(ServletFileUpload.isMultipartContent(request)) {
            // 전송 파일 용량 제한 : 10MB로 제한되어 있다. 그 이상은 유료
            int maxSize = 1024 * 1024; // (1mb)로 설정
           
            String root = request.getSession().getServletContext().getRealPath("/");
            System.out.println(root); // 톰캣 설정 첫번째 항목 체크를 안하면 경로가 톰캣으로 잡혀버린다.
            // thumbnale_uploadFiles 라는 폴더가 해당 경로 아래에 생기게 되므로 다음과 같이 파일 경로를 설정하자
           
            String filePath = root + "thumbnale_uploadFiles/";
           
            // MultipartRequest multiRequest = new MultipartRequest(request, filePath, maxSize, "UTF-8", new DefaultFileRenamePolicy());            // 사용자가 올린 파일명을 그대로 저장하지 않는 것이 일반적이다.
            // 1. 같은 파일명이 있는 경우 이전 파일을 덮어 쓸 수 있다.
            // 2. 한글로된 파일명, 특수기호, 띄어쓰기는 서버에 따라 문제가 생길 여지가 있다.
            // DefaultFileRenamePolicy는 cos.jar에서 제공하는 클래스
            // 같은 파일명이 존재하는지를 체크하고 있을 경우에는 뒤에 숫자를 붙여준다.
            // ex) aaa.zip, aaa1.zip, aaa2.zip
            MultipartRequest multiRequest = new MultipartRequest(request, filePath, maxSize, "UTF-8", new MyFileRenamePolicy());
           
            // 다중 파일을 묶어서 업로드 하기 위해 컬렉션 사용
            // 저장한 파일의 이름을 저장할 arrayList 생성
            ArrayList<String> saveFiles = new ArrayList<String>();
           
            // 원본 파일의 이름을 저장 할 ArrayList 생성
            ArrayList<String> originFiles = new ArrayList<String>();
           
            // 각 파일의 정보를 구해온 뒤 DB에 저장할 목적의 데이터를 꺼내온다.
            Enumeration<String> files = multiRequest.getFileNames();
           
            while (files.hasMoreElements()) {
                String name = files.nextElement();
               
                System.out.println(name);
               
                saveFiles.add(multiRequest.getFilesystemName(name));
                originFiles.add(multiRequest.getOriginalFileName(name));
               
                System.out.println("FileSystem name : " + multiRequest.getFilesystemName(name));
                System.out.println("originFile name : " + multiRequest.getOriginalFileName(name));
            }
           
            String multiTitle = multiRequest.getParameter("title");
            String multiContent = multiRequest.getParameter("content");
            System.out.println(multiTitle);
            System.out.println(multiContent);
           
            //Board객체 생성
            Board b = new Board();
            b.setbTitle(multiTitle);
            b.setbContent(multiContent);
            b.setbWriter(String.valueOf(((Member)(request.getSession().getAttribute("loginUser"))).getUno()));
           
            // Attachment 객체 생성하여 arrayList 객체 생성
            ArrayList<Attachment> fileList = new ArrayList<Attachment>();
           
            for(int i = originFiles.size() - 1; i >= 0; i--) {
                Attachment at = new Attachment();
                at.setFilePath(filePath);
                at.setOriginName(originFiles.get(i));
                at.setChangeName(saveFiles.get(i));
               
                fileList.add(at);
               
            }
           
            int result = new BoardService().insertThumbnail(b, fileList);
           
            if (result > 0) {
                response.sendRedirect(request.getContextPath() + "/selectList.tn");
            } else {
                // 실패 시 저장된 사진 삭제
                for (int i = 0; i < saveFiles.size(); i++) {
                    // 파일 시스템에 저장된 이름으로 파일 객체 생성
                    File failedFile = new File(filePath + saveFiles.get(i));
                   
                    // true, false를 리턴함
                    failedFile.delete();
                }
               
                request.setAttribute("msg", "사진게시판 등록 실패!");
                request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response);
            }
           
           
        }
       
       
    }
   
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

------------------------------------------------------------------------------------------------------------------------------------


        // cos.jar가 파일도 받고 다른 값들도 받아주는 역할을 한다.
        // com.oreilly.servlet의 약자이다.
        // http://servlets.com/cos/ 맨 아래에서 다운로드해서 lib에 추가한다.


부분은 사진으로 추가 설명


http://servlets.com/cos/ 링크로 이동




다운받은 압축파일을 풀어 lib폴더에 복사하면 된다.


대부분의 설명은 주석에 되어 있으므로 안 되있는 부분만 설명




Enumeration<String> files = multiRequest.getFileNames(); 경우는 파일을 리스트 형식으로 알아서 불러오는 객체이다.







서블릿 부분에서 데이터를 정리해서 DB 쪽으로 연결하는 코드는 아래 한 줄 부분이다.

int result = new BoardService().insertThumbnail(b, fileList);




다음은 Service 부분

------------------------------------------------------------------------------------------------------------------------------------

public int insertThumbnail(Board b, ArrayList<Attachment> fileList) {
        Connection con = getConnection();
       
        int result = 0;
       
        int result1 = new BoardDao().insertThumbnailContent(con, b);
       
        if (result1 > 0) {
            int bid = new BoardDao().selectCurrval(con);
           
            for(int i = 0; i < fileList.size(); i++) {
                fileList.get(i).setBid(bid);
            }
        }
       
        int result2 = new BoardDao().insertAttachment(con, fileList);
       
        if (result1 > 0 && result2 > 0) {
            commit(con);
            result = 1;
        } else {
            rollback(con);
        }
       
        close(con);
       
       
        return result;
    }

------------------------------------------------------------------------------------------------------------------------------------

이 부분에서는 DB에 3번의 접근이 일어나게 된다.


첫번째는 게시글 테이블에 등록


두번째는 게시글 번호 불러오기(시퀀스를 통해서 등록한 게시글 번호를 불러온다.)


세번째는 첨부파일 테이블에 게시글 번호(외래키)와 함께 파일을 등록한다.







Dao 부분은 전과 같이 DB에 Prestatement나 statement를 사용하여 쿼리문을 사용한다.

여태껏 해온 부분과 비슷하므로 생략


블로그의 예제들에서는 여태까지 DataBase에 비밀번호를 입력한 그대로 저장하여 그대로 불러왔다.


하지만 법적으로?? 비밀번호는 그대로 저장하면 안되고 입력받고 값을


전달 받으면 암호화 하여서 데이터베이스에 저장해야 한다고 한다.





왜냐하면 해커에게 공격을 당한다면 보통 DB가 타겟이 되는데


DB에 암호가 그대로 쓰여져 있다면 개인정보 뿐만 아니라 암호까지 그대로 전달되어 버린다.


그러므로 비밀번호는 절대 그대로 저장하면 안된다.





JSP에서 비밀번호를 암호화 하는 구조는 다음과 같다.


기존의 MVC를 적용한 구조가 [View - 비밀번호 입력 ->> Controller(Servlet) - 비밀번호를 받음 ->> Service ->> Dao ] 순으로 전달이 되는 구조인데


암호화 (Wrapper : 포장, 싸다)를 적용하면 다음과 같은 구조가 된다.


[View - 비밀번호 입력 ->> Wrapper(Filter), 비밀번호 암호화 ->> Controller(Servlet) - 암호화된 비밀번호를 받음 ->> Service ->> Dao ]


비밀번호를 입력 받자마자 포장하여 암호화 하고 DB에 전달해서 저장하는 것이다.



같은 값을 암호화 했을때 나오는 문구들은 결과가 똑같기 때문에

변경된 값을 비교하여 같으면 로그인에 성공하는 방식이다.






이 구조의 전제로는 암호화 알고리즘이 단방향 알고리즘이여야 한다.


단방향 : 암호화만 할 수 있고 복호화(원상 복구)는 불가능하다. 암호화된 결과를 digest라고 부른다.


양방향 : 암호화 할 수 있고 복호화 또한 가능하다.







이번의 예는 sha - 512 알고리즘을 사용하는데 정부 기관에서는 sha 256 이상 버전의 알고리즘을 권장하고 있다고 한다.


256, 512는 눈치가 빠르다면 2진수 비트수를 의미한다는 것을 눈치 챘을 것이다.







예의 프로젝트 구조는 다음과 같다.





구조를 보면 매우 복잡하다.


그러므로 암호화, Filter 관련 파일만 올린다.


나머지는 여태까지 했던 기능들과 별반 다를게 없다.


암호화에 사용하게될 클래스들은 filter 폴더와 wrapper 폴더가 된다.


다른 클래스에서는 따로 명시할 코드가 전혀 없고 여태까지 쓰던대로와 같기 때문에 설명은 생략









먼저 Filter 파일에 대한 이해가 필요하다.


생성방법은 다음과 같다.




프로젝트 네비게이터에서 만들 폴더에


우클릭 - New - Filter File 이나


우클릭 - New - Other을 눌러 다음과 같이 검색하면 된다.




선택 한 후









이와같이 설정하면 된다.


서블릿과 매우 비슷하다.


해당 2번째 사진에는 Filter mappings에 /CommonFilter을 더블클릭해서 변경하는 팝업창인데


Pattern에 '/'가 아닌 '/*'를 입력해야 한다.






생성된 필터의 내용 또한 서블릿과 비슷하다.


필터 클래스는 지정한 페이지 링크가 열리면 서블릿보다 먼저 request, response 데이터를 받아서 데이터를 수정하고


실제 이동할 서블릿에 수정된 데이터를 넘기는 것이다.


암호화를 이 부분에서 적용한다.





위 문단에서 설명한 지정한 페이지란 Filter 클래스 생성 시 정한 Pattern /* 가 된다.


클래스 상단에 보면 서블릿과 똑같이 어노테이션으로 @WebFilter("/*")라고 쓰여있다.


여기서 지정한 /*란 "/로 시작하는 모든 링크(*의 의미)"라고 생각하면 된다.


다음 필터 파일은 모든 페이지에서 request, response가 발생한다면 그 데이터를 UTF-8 CharSet 설정을 하고 전달하는 것이다.

이로 인해 데이터를 받을 Servlet에서 request.setCharacterEncoding("UTF-8");를 입력 할 필요가 없다.



CommonFilter.java

------------------------------------------------------------------------------------------------------------------------------------

package com.kh.jsp.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("/*") // '/*'이 url패턴은 슬러쉬 뒤에 어떤 링크가 와도 모든 페이지에 이 필터가 적용이 된다라는 뜻(모든 페이지는 열 때 /가 붙는다.)
public class CommonFilter implements Filter {

    public CommonFilter() {
        System.out.println("필터 생성!");
    }

    public void destroy() {
       
    }
   
    // doget과 비슷
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8"); // 여기서 UTF-8을 지정하였기 때문에 서블릿에서 UTF-8을 지정 할 필요가 없어진다.
        response.setContentType("text/html; charset=UTF-8");
       
       
        chain.doFilter(request, response); // 다음 필터로 정보를 전달함
    }
   
    //시작 시 한번 실행
    public void init(FilterConfig fConfig) throws ServletException {
       
    }

}

------------------------------------------------------------------------------------------------------------------------------------



코드를 쭉 보면 서블릿과 비슷한 메소드들이 등장한다.


이것들의 라이프 사이클 또한 서블릿과 똑같다.


doFilter 메소드는 doGet과 같은 메소드라고 생각하면 된다. 필터가 호출되면 실행되는 문구이다.







Filter는 서버가 실행되면 같이 생성되기 때문에 생성자 CommonFilter에 입력된 코드는


서버를 동작한다면 같이 실행되게 된다.









다음으로 이 Filter를 이용한 암호화 클래스 작성이다.



IncryptFilter.java

------------------------------------------------------------------------------------------------------------------------------------

package com.kh.jsp.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.jsp.wrapper.LoginWrapper;

@WebFilter("*.me") // 뒤에가 .me가 되는 페이지에 전달되는 정보가 필터를 적용
// 어노테이션 말고 xml에 하면 필터의 우선순위 설정 가능
public class IncryptFilter implements Filter {

    public IncryptFilter() {
        System.out.println("나도 객체 생성!!");
    }

    public void destroy() {
       
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // ServletRequest - 부모 / HttpServletRequest - 자식 관계
        HttpServletRequest hRequest = (HttpServletRequest)request;
       
        LoginWrapper lw = new LoginWrapper(hRequest);
       
       
       
        chain.doFilter(lw, response);
    }

    public void init(FilterConfig fConfig) throws ServletException {
       
    }

}

------------------------------------------------------------------------------------------------------------------------------------

이 Filter의 패턴은 '/*.me'인데 해석하자면 /로 시작하고 .me로 끝나는 페이지는 전부 이 필터를 거치게 된다.

LoginWrapper이라는 객체를 생성하여 request로 들어온 정보를 보낸다.(보통 사용자가 입력한 정보가 들어오게 될 것이다.)

이 후 LoginWrapper 클래스를 생성해서 HttpServletRequestWrapper라는 객체를 상속 받게하여 암호화 알고리즘을 적용한다.





LoginWrapper.java

------------------------------------------------------------------------------------------------------------------------------------

package com.kh.jsp.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 LoginWrapper extends HttpServletRequestWrapper{

    public LoginWrapper(HttpServletRequest request) {
        super(request);
    }
   
    @Override
    public String getParameter(String key) {
        String value = "";
       
        if (key != null && key.equals("userPwd")) {
            value = getSha512(super.getParameter("userPwd"));
        } else {
            value = super.getParameter(key);
        }
       
       
        return value;
    }
    private static String getSha512(String pwd) {
        String encPwd = "";
       
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] bytes = pwd.getBytes(Charset.forName("UTF-8"));
            md.update(bytes);
           
            encPwd = Base64.getEncoder().encodeToString(md.digest());
           
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
       
       
        return encPwd;
    }
   
}

------------------------------------------------------------------------------------------------------------------------------------


LoginWrapper 객체는 HttpServletRequestWrapper를 상속받았기 때문에


request.getParameter("~") 처럼 getParameter 메소드를 사용 할 수 있다.


오버라이딩으로 getParameter 메소드를 변경하여 Key값이 비밀번호 일 경우(userPwd)


getSha512 메소드를 통해서 암호화 알고리즘을 적용한 값으로 userPwd의 value 값을 바꿔버린다.







MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] bytes = [바꿀 문자열 값].getBytes(Charset.forName("UTF-8"));
md.update(bytes);
           
[반환할 String 변수방] = Base64.getEncoder().encodeToString(md.digest());


암호화 코드는 위와 같은데 그냥 복사해서 [ ]안에 값만 조정해서 쓰면 된다.





왜냐하면 위의 코드를 이해하려면


암호화 할 알고리즘이 어떤 방식으로 돌아가는지 알아야 한다.


어떤 방식으로 돌아가는지 알게 된다면 암호화 한 값을 복호화(복구)하기 쉬워지기 때문에


공개되지 않는다.


그러므로 그냥 그대로 갓다 쓰자.








이번 프로젝트는 로그인, 회원가입, 정보수정, 탈퇴, 로그아웃을 만들어 본다.


기능은 거의 전과 비슷하다.


폴더 구조는 다음과 같다.





전에 사용했던 기술들은 모두 사용한다.


사진에는 안나와 있지만 WEB-INF 아래 lib 폴더에 ojdbc6.jar 파일이 있다.


시작페이지(form)


로그인 폼이 있다.

------------------------------------------------------------------------------------------------------------------------------------

index.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
    html{
        height: 100%;
    }
    body {
        background: skyblue;
        height: 100%;
    }
    #main{
        min-height: 90%;
    }
    h1{
        color: navy;
    }
    #title{
        color: orangered;
    }
    input[type='submit'] {
        height: 50px;
        background: orangered;
        color: white;
        border-radius: 10px;
    }
</style>
</head>
<body>
    <div id="main">
        <h1 align="center">Welcome to <label id="title">둘리's World</label></h1>
       
        <div>
            <form action="<%=request.getContextPath() %>/login" method="post">
                <table align="center">
                    <tr>
                        <td><label>ID</label></td>
                        <td colspan="2"><input type="text" name="userId"></td>
                        <td rowspan="2"><input type="submit" value="LOGIN"></td>
                    </tr>
                    <tr>
                        <td><label>PWD</label></td>
                        <td colspan="2"><input type="password" name="password"></td>
                    </tr>
                    <tr>
                        <td colspan="4"><a href="views/member/memberJoinForm.jsp">회원가입하기</a></td>
                    </tr>
                    <tr>
                        <td colspan="4"><a href="#">아이디 / 비밀번호 찾기</a></td>
                    </tr>
                </table>
            </form>
        </div>
    </div>
   
   
    <%@ include file="views/common/footer.jsp" %>
   
</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------


회원가입(form, servlet)


------------------------------------------------------------------------------------------------------------------------------------

memberJoinForm.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1 align="center">회원가입</h1>
    <form action="<%= request.getContextPath() %>/insertMember" method="post">
        <table align="center">
            <tr>
                <td><label>아이디</label></td>
                <td><input type="text" name="userId"></td>
            </tr>
            <tr>
                <td><label>비밀번호</label></td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td><label>비밀번호 확인</label></td>
                <td><input type="password" name="password2"></td>
            </tr>
            <tr>
                <td><label>이름</label></td>
                <td><input type="text" name="userName"></td>
            </tr>
            <tr>
                <td><label>나이</label></td>
                <td><input type="number" name="age"></td>
            </tr>
            <tr>
                <td>성별</td>
                <td>
                    <input type="radio" name="gender" value="M" id="male">
                    <label for="male">남</label>
                    <input type="radio" name="gender" value="F" id="female">
                    <label for="female">여</label>
                </td>
            </tr>
            <tr>
                <td><label>이메일</label></td>
                <td><input type="email" name="email"></td>
            </tr>
            <tr>
                <td><label>전화번호</label></td>
                <td><input type="tel" name="phone"></td>
            </tr>
            <tr>
                <td><label>주소</label></td>
                <td><input type="text" name="address"></td>
            </tr>
            <tr>
                <td><label>취미</label></td>
                <td>
                    <input type="checkbox" name="hobby" value="운동" id="sports">
                    <label for="sports">운동</label>
                    <input type="checkbox" name="hobby" value="낚시" id="fishing">
                    <label for="sports">낚시</label>
                    <input type="checkbox" name="hobby" value="등산" id="climbing">
                    <label for="sports">등산</label>
                    <input type="checkbox" name="hobby" value="요리" id="cooking">
                    <label for="sports">요리</label>
                </td>
            </tr>
            <tr align="center">
                <td colspan="2">
                    <input type="reset" value="리셋"> &nbsp; &nbsp;
                    <input type="submit" value="가입하기">
                </td>
            </tr>
        </table>
    </form>
</body>
</html>




InsertMemberServlet.java



package com.kh.w7.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.w7.member.model.service.MemberService;
import com.kh.w7.member.model.vo.Member;

@WebServlet("/insertMember")
public class InsertMemberServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
   
    public InsertMemberServlet() {
        super();
    }
   
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 인코딩
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
       
        // 2. request에서 파라미터 값 꺼내기
        String userId = request.getParameter("userId");
        String password = request.getParameter("password");
        String userName = request.getParameter("userName");
        String gender = request.getParameter("gender");
        int age = Integer.parseInt(request.getParameter("age"));
        String email = request.getParameter("email");
        String phone = request.getParameter("phone");
        String address = request.getParameter("address");
        String[] hobby = request.getParameterValues("hobby");
       
        String hobbies = "";
        for (int i = 0; i < hobby.length; i++) {
            if (i == 0) {
                hobbies += hobby[i];
            }else {
                hobbies += ", " + hobby[i];
            }
        }
       
        // 3. Member 객체 생성
        Member reqMember = new Member();
        reqMember.setUserId(userId);
        reqMember.setPassword(password);
        reqMember.setUserName(userName);
        reqMember.setGender(gender);
        reqMember.setAge(age);
        reqMember.setEmail(email);
        reqMember.setPhone(phone);
        reqMember.setAddress(address);
        reqMember.setHobby(hobbies);
       
       
        // 4. Service 로직으로 전달
        int result = new MemberService().insertMember(reqMember);
       
        if(result > 0) {
            String page = "views/common/successPage.jsp";
            request.getSession().setAttribute("msg", "회원 가입에 성공하셨습니다.");
            response.sendRedirect(page);
        }else {
            String page = "views/common/errorPage.jsp";
            request.setAttribute("msg", "회원 가입에 실패하셨습니다!");
           
            RequestDispatcher view = request.getRequestDispatcher(page);
            view.forward(request, response);
        }
       
       
       
       
    }
   
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

------------------------------------------------------------------------------------------------------------------------------------


로그인(servlet)


------------------------------------------------------------------------------------------------------------------------------------

LoginServlet.java



package com.kh.w7.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 javax.servlet.http.HttpSession;

import com.kh.w7.member.model.service.MemberService;
import com.kh.w7.member.model.vo.Member;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
      
    public LoginServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 전송값에 한글이 있는 경우 인코딩 처리 해야 함
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
       
        // 2. 전송값 꺼내서 변수에 기록하기
        String userId = request.getParameter("userId");
        String password = request.getParameter("password");
       
        System.out.println("ID : " + userId);
        System.out.println("PW : " + password);
       
        Member reqMember = new Member();
       
        reqMember.setUserId(userId);
        reqMember.setPassword(password);
       
        // 3. 서비스 로직 호출
        Member loginUser = new MemberService().loginCheck(reqMember);
       
       
        // 4. 받은 결과에 따라 뷰 페이지 내보내기
        String page = "";
        if (loginUser != null) { // 성공
           
            HttpSession session = request.getSession();
            session.setAttribute("loginUser", loginUser);
           
            page = "views/main/main.jsp";
           
        }else {                     // 실패
           
            request.setAttribute("msg", "로그인 실패!");
            page = "views/common/errorPage.jsp";
           
        }
       
        RequestDispatcher view = request.getRequestDispatcher(page);
        view.forward(request, response);
       
       
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

------------------------------------------------------------------------------------------------------------------------------------


메인 페이지, 성공, 에러 페이지(form), 로그아웃(servlet)


------------------------------------------------------------------------------------------------------------------------------------

main.jsp



<%@page import="com.kh.w7.member.model.vo.Member"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%-- <% Member loginUser = (Member)session.getAttribute("loginUser"); %> --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <%@ include file="../common/menubar.jsp" %>
    <%-- <h1><% out.println(loginUser.getUserName()); %></h1> --%>
   
</body>
</html>




menubar.jsp(실질적인 메인)



<%@page import="com.kh.w7.member.model.vo.Member"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    Member loginUser = (Member)session.getAttribute("loginUser");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
    div > button {
        float: right;
    }
   
</style>
</head>
<body>
    <h1 align="center">메인화면</h1>
    <h3 align="right"><%= loginUser.getUserName() %>님 환영합니다.</h3>
    <div>
        <button onclick="logout()">로그아웃</button>
        <% if(!loginUser.getUserId().equals("admin")){ %>
            <button onclick="location.href='/w7/views/member/memberUpdateForm.jsp'">내 정보 수정</button>
        <% }else {%>
            <button>관리자 메뉴로</button>
        <% } %>
    </div>
   
    <script type="text/javascript">
        function logout() {
            var check = window.confirm("로그아웃 하시겠습니까?");
           
            if(check == true){
                location.href="<%= request.getContextPath() %>/logout";
               
            }
        }
    </script>
</body>
</html>




errorPage.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% String msg = (String)request.getAttribute("msg"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>에러 발생!</h1>
    <h3><%= msg %></h3>
</body>
</html>






successPage.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String msg = (String)session.getAttribute("msg");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1><%= msg %></h1>
    <a href="/w7/index.jsp">메인으로 이동</a>
</body>
</html>








LogoutServlet.java



package com.kh.w7.member.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
      
    public LogoutServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().invalidate();
       
        response.sendRedirect("index.jsp");
    }

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

}

------------------------------------------------------------------------------------------------------------------------------------


정보수정, 탈퇴(form, servlet)


계정삭제는 서블릿을 따로 만들지 않고 UpdateForm 스크립트에 했다.

------------------------------------------------------------------------------------------------------------------------------------

memberUpdateForm.jsp



<%@page import="com.kh.w7.member.model.service.MemberService"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.kh.w7.member.model.vo.Member"%>
<% Member loginUser = (Member)session.getAttribute("loginUser"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
    <h1 align="center"><%= loginUser.getUserName() %>님의 회원 정보 수정<button onclick="deleteMember()">탈퇴하기</button></h1>
   
    <script type="text/javascript">
        function deleteMember() {
            <%
                int result = 0;
           
                result = new MemberService().deleteMember(loginUser);
           
                if(result > 0){
                    session.invalidate();
            %>
                    alert("계정이 삭제되었습니다.");
                    window.location.href = '../../index.jsp';
            <%
                }else{
            %>
                    alert("계정 삭제에 실패했습니다.");
            <%
                }
            %>
           
        }
    </script>
   
    <form action="<%= request.getContextPath() %>/updateMember" method="post">
        <table align="center">
            <tr>
                <td><label>아이디</label></td>
                <td><input type="text" name="userId" value="<%= loginUser.getUserId() %>" readonly></td>
            </tr>
            <tr>
                <td><label>비밀번호</label></td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td><label>비밀번호 확인</label></td>
                <td><input type="password" name="password2"></td>
            </tr>
            <tr>
                <td><label>이름</label></td>
                <td><input type="text" name="userName" value="<%= loginUser.getUserName() %>"></td>
            </tr>
            <tr>
                <td><label>나이</label></td>
                <td><input type="number" name="age" value="<%= loginUser.getAge() %>"></td>
            </tr>
            <tr>
                <td>성별</td>
                <td>
                    <% if(loginUser.getGender().equals("M")){%>
                        <input type="radio" name="gender" value="M" id="male" checked>
                        <label for="male">남</label>
                        <input type="radio" name="gender" value="F" id="female">
                        <label for="female">여</label>
                    <% }else { %>
                        <input type="radio" name="gender" value="M" id="male">
                        <label for="male">남</label>
                        <input type="radio" name="gender" value="F" id="female" checked>
                        <label for="female">여</label>
                    <% } %>
                </td>
            </tr>
            <tr>
                <td><label>이메일</label></td>
                <td><input type="email" name="email" value="<%= loginUser.getEmail() %>"></td>
            </tr>
            <tr>
                <td><label>전화번호</label></td>
                <td><input type="tel" name="phone" value="<%= loginUser.getPhone() %>"></td>
            </tr>
            <tr>
                <td><label>주소</label></td>
                <td><input type="text" name="address" value="<%= loginUser.getAddress() %>"></td>
            </tr>
            <tr>
                <td><label>취미</label></td>
                <td>
                    <input type="checkbox" name="hobby" value="운동" id="sports">
                    <label for="sports">운동</label>
                    <input type="checkbox" name="hobby" value="낚시" id="fishing">
                    <label for="sports">낚시</label>
                    <input type="checkbox" name="hobby" value="등산" id="climbing">
                    <label for="sports">등산</label>
                    <input type="checkbox" name="hobby" value="요리" id="cooking">
                    <label for="sports">요리</label>
                </td>
            </tr>
            <tr align="center">
                <td colspan="2">
                    <input type="reset" value="리셋"> &nbsp; &nbsp;
                    <input type="submit" value="변경하기">
                </td>
            </tr>
        </table>
       
        <script type="text/javascript">
            $(function() {
                var arr = '<%= loginUser.getHobby() %>'.split(", ");
               
                $("input[name=hobby]").each(function() {
                    for (var i = 0; i < arr.length; i++) {
                        if ($(this).val() === arr[i]) {
                            $(this).attr("checked", true);
                        }else{
                           
                        }
                    }
                });
            });
           
           
        </script>
       
    </form>
</body>
</html>







UpdateMemberServlet.java



package com.kh.w7.member.controller;

import java.io.IOException;
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 javax.servlet.http.HttpSession;

import com.kh.w7.member.model.service.MemberService;
import com.kh.w7.member.model.vo.Member;

@WebServlet("/updateMember")
public class UpdateMemberServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
      
    public UpdateMemberServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //인코딩
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
       
        //request객체에서 parameter꺼내기
       
        String userId = request.getParameter("userId");
        String password = request.getParameter("password");
        String userName = request.getParameter("userName");
        String gender = request.getParameter("gender");
        int age = Integer.parseInt(request.getParameter("age"));
        String email = request.getParameter("email");
        String phone = request.getParameter("phone");
        String address = request.getParameter("address");
        String[] hobby = request.getParameterValues("hobby");
       
        String hobbies = "";
        for (int i = 0; i < hobby.length; i++) {
            if (i == 0) {
                hobbies += hobby[i];
            }else {
                hobbies += ", " + hobby[i];
            }
        }
       
        //reqMember 객체 생성
        Member reqMember = new Member(userId, password, userName, gender, age, email, phone, address, hobbies);
       
        //service 로직으로 전달
        int result = new MemberService().updateMember(reqMember);
       
        //처리 결과에 따른 뷰 페이지 결정
        if (result > 0) {
            HttpSession session = request.getSession();
            session.setAttribute("loginUser", reqMember);
            response.sendRedirect("views/member/memberUpdateForm.jsp");
           
        }
    }

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

}

------------------------------------------------------------------------------------------------------------------------------------


모델(vo, service, dao)


------------------------------------------------------------------------------------------------------------------------------------

Member.java



package com.kh.w7.member.model.vo;

import java.sql.Date;

public class Member implements java.io.Serializable{
    private String userId;
    private String password;
    private String userName;
    private String gender;
    private int age;
    private String email;
    private String phone;
    private String address;
    private String hobby;
    private Date enrollDate;
   
    public Member() {}

    public Member(String userId, String password, String userName, String gender, int age, String email, String phone,
            String address, String hobby, Date enrollDate) {
        super();
        this.userId = userId;
        this.password = password;
        this.userName = userName;
        this.gender = gender;
        this.age = age;
        this.email = email;
        this.phone = phone;
        this.address = address;
        this.hobby = hobby;
        this.enrollDate = enrollDate;
    }

    public Member(String userId, String password, String userName, String gender, int age, String email, String phone,
            String address, String hobby) {
        super();
        this.userId = userId;
        this.password = password;
        this.userName = userName;
        this.gender = gender;
        this.age = age;
        this.email = email;
        this.phone = phone;
        this.address = address;
        this.hobby = hobby;
    }
   
   

    @Override
    public String toString() {
        return "Member [userId=" + userId + ", password=" + password + ", userName=" + userName + ", gender=" + gender
                + ", age=" + age + ", email=" + email + ", phone=" + phone + ", address=" + address + ", hobby=" + hobby
                + ", enrollDate=" + enrollDate + "]";
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public Date getEnrollDate() {
        return enrollDate;
    }

    public void setEnrollDate(Date enrollDate) {
        this.enrollDate = enrollDate;
    }
   
   
   
}





MemberService.java



package com.kh.w7.member.model.service;

import java.sql.Connection;

import com.kh.w7.member.model.dao.MemberDao;
import com.kh.w7.member.model.vo.Member;
import static com.kh.w7.common.JDBCTemplate.*;

public class MemberService {
   
    // 로그인용 메소드
    public Member loginCheck(Member reqMember) {
        Connection con = getConnection();
       
        System.out.println(con);
       
        Member loginUser = new MemberDao().loginCheck(con, reqMember);
       
        close(con);
       
        return loginUser;
    }

    public int insertMember(Member reqMember) {
        Connection con = getConnection();
       
        System.out.println(con);
       
        int result = new MemberDao().insertMember(con, reqMember);
       
        if (result > 0) {
            commit(con);
        }else {
            rollback(con);
        }
       
        close(con);
       
        return result;
    }

    public int updateMember(Member reqMember) {
        Connection con = getConnection();
       
        System.out.println(con);
       
        int result = new MemberDao().updateMember(con, reqMember);
       
        if (result > 0) {
            commit(con);
        }else {
            rollback(con);
        }
       
        close(con);
       
        return result;
    }
   
    public int deleteMember(Member reqMember) {
        Connection con = getConnection();
       
        System.out.println(con);
       
        int result = new MemberDao().deleteMember(con, reqMember.getUserId());
       
        if (result > 0) {
            commit(con);
        }else {
            rollback(con);
        }
       
        close(con);
       
        return result;
    }

}







MemberDao.java



package com.kh.w7.member.model.dao;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import com.kh.w7.member.model.vo.Member;
import static com.kh.w7.common.JDBCTemplate.*;

public class MemberDao {
   
    private Properties prop = new Properties();

    public MemberDao() {
        String fileName = MemberDao.class.getResource("/sql/member/member-query.properties").getPath();
               
        try {
            prop.load(new FileReader(fileName));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   
    public Member loginCheck(Connection con, Member reqMember) {
        PreparedStatement pstmt = null;
        ResultSet rset = null;
        Member loginUser = null;
       
        String query = prop.getProperty("loginCheck");
       
        try {
            pstmt = con.prepareStatement(query);
            pstmt.setString(1, reqMember.getUserId());
            pstmt.setString(2, reqMember.getPassword());
           
            rset = pstmt.executeQuery();
           
            if (rset.next()) {
                loginUser = new Member();
               
                loginUser.setUserId(rset.getString("USER_ID"));
                loginUser.setPassword(rset.getString("PASSWORD"));
                loginUser.setUserName(rset.getString("USER_NAME"));
                loginUser.setGender(rset.getString("GENDER"));
                loginUser.setAge(rset.getInt("AGE"));
                loginUser.setEmail(rset.getString("EMAIL"));
                loginUser.setPhone(rset.getString("PHONE"));
                loginUser.setAddress(rset.getString("ADDRESS"));
                loginUser.setHobby(rset.getString("HOBBY"));
                loginUser.setEnrollDate(rset.getDate("ENROLL_DATE"));
               
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(rset);
            close(pstmt);
        }
       
        return loginUser;
    }

    public int insertMember(Connection con, Member reqMember) {
        PreparedStatement pstmt = null;
        int result = 0;
       
        String query = prop.getProperty("insertMember");
       
        try {
            pstmt = con.prepareStatement(query);
            pstmt.setString(1, reqMember.getUserId());
            pstmt.setString(2, reqMember.getPassword());
            pstmt.setString(3, reqMember.getUserName());
            pstmt.setString(4, reqMember.getGender());
            pstmt.setInt(5, reqMember.getAge());
            pstmt.setString(6, reqMember.getEmail());
            pstmt.setString(7, reqMember.getPhone());
            pstmt.setString(8, reqMember.getAddress());
            pstmt.setString(9, reqMember.getHobby());
           
            result = pstmt.executeUpdate();
       
       
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(pstmt);
        }
        return result;
    }

    public int updateMember(Connection con, Member reqMember) {
        PreparedStatement pstmt = null;
        int result = 0;
       
        String query = prop.getProperty("updateMember");
       
        try {
            pstmt = con.prepareStatement(query);
           
            pstmt.setString(1, reqMember.getPassword());
            pstmt.setString(2, reqMember.getUserName());
            pstmt.setString(3, reqMember.getGender());
            pstmt.setInt(4, reqMember.getAge());
            pstmt.setString(5, reqMember.getEmail());
            pstmt.setString(6, reqMember.getPhone());
            pstmt.setString(7, reqMember.getAddress());
            pstmt.setString(8, reqMember.getHobby());
            pstmt.setString(9, reqMember.getUserId());
           
           
            result = pstmt.executeUpdate();
           
           
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(pstmt);
        }
        return result;
    }

    public int deleteMember(Connection con, String userId) {
        PreparedStatement pstmt = null;
        int result = 0;
       
        String query = prop.getProperty("deleteMember");
       
        try {
            pstmt = con.prepareStatement(query);
           
            pstmt.setString(1, userId);
           
            result = pstmt.executeUpdate();
           
           
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(pstmt);
        }
        return result;
    }

}

------------------------------------------------------------------------------------------------------------------------------------


그 외 (Properties, Template, footer)


------------------------------------------------------------------------------------------------------------------------------------

JDBCTemplate.java



package com.kh.w7.common;

import java.io.FileReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCTemplate {
    public static Connection getConnection() {
        Connection conn = null;
        Properties prop = new Properties();
       
        String fileName = JDBCTemplate.class.getResource("/sql/driver.properties").getPath();
               
        System.out.println(fileName);
       
        try {
            prop.load(new FileReader(fileName));
            String driver = prop.getProperty("driver");
            String url = prop.getProperty("url");
            String user = prop.getProperty("user");
            String password = prop.getProperty("password");
           
            // 아래 클래스 구문은 신버전에서는 자동으로 추가되어서 생략해도 되지만
            // 구버전 호환을 위해 명시해두자.
            Class.forName(driver);
           
            conn = DriverManager.getConnection(url, user, password);
           
            conn.setAutoCommit(false);
           
            System.out.println(conn);
           
        } catch (Exception e) {
            e.printStackTrace();
        }
        // prop 파일을 수정할 때 classes 폴더 아래의 파일을 수정하면 서버 껏따 킬때 재생성 되기 때문에 사라진다.
        // 그리고 바로바로 수정사항이 적용이 안될 때도 있는데 메뉴바 상단의 Project - clean을 실행하면 강제 재컴파일 시켜준다.
       
        return conn;
    }
   
    public static void close(Connection con) {
        try {
            if(con != null && !con.isClosed()) {
                con.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void close(Statement stmt) {
        try {
            if(stmt != null && !stmt.isClosed()) {
                stmt.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void close(ResultSet rset) {
        try {
            if(rset != null && !rset.isClosed()) {
                rset.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void commit(Connection con) {
        try {
            if(con != null && !con.isClosed()) {
                con.commit();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void rollback(Connection con) {
        try {
            if(con != null && !con.isClosed()) {
                con.rollback();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}





driver.properties


driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=jsp
password:jsp



member-query.properties


loginCheck=SELECT * FROM member WHERE user_id=? AND password=?
insertMember=INSERT INTO member VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, SYSDATE)
updateMember=UPDATE member SET password = ?, user_name = ?, gender = ?, age = ?, email = ?, phone = ?, address = ?, hobby = ? WHERE user_id = ?
deleteMember=DELETE FROM member WHERE user_id = ?







footer.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
    hr {
        color: gray;
    }
    p {
        text-align: center;
    }
</style>
</head>
<body>
    <hr>
    <p>Copyright, All right reserved</p>
</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------





특별한 기능은 없다.


전부 전에 설명했던 기능들을 짜집기하여 만든 예시이다.


로그아웃 시 Session을 invalidate 하여 삭제한다.




MVC 패턴을 적용한 이번 예의 구조를 살펴보자





폴더의 수가 많고 매우 복잡해 보이지만


파일 하나하나가 잘 분류되어 어떤 기능을 하는지 예상이 된다.


WEB-INF / lib / ojdbc6.jar 파일은 예5 게시글과 같이 끌어오면 된다.





이번 예는 DB를 조회, 입력하여 로그인, 회원가입, 로그아웃을 만들어보자.


새로 나오는 개념은 Session이라는 개념으로 로그인을 성공 했을 경우 로그인의 정보들(계정정보 등)을


담아두어 여러 페이지에서 사용 할 수 있는 방이라고 생각하면 된다.


예를 들어서 네이버에 로그인을 하고 아무 활동도 안하고 시간이 지나면 "세션이 만료되었습니다." 하고 자동 로그아웃 된다.


세션은 로그인 시점부터 관련 정보를 Session을 통해서 담고 있다가


설정해둔 일정 시간이 지나면 파기하게끔 설정해둔 것이다.


파기가 되면 로그아웃 처리가 되는것이다.






그리고 이번에는 java를 공부할 때 다루었던 Properties 파일을 이용해서


반복적으로 사용할 키워드들을 Key, Value 형태로 다룬다.


예에서는 서버의 jdbc.oracle~~~이나 oracle:jdbc:thin과 같이 쓰기 귀찮은 구문을 미리 입력해둔다.










예를 확인해보자.




먼저 로그인폼


index.jsp, loginForm.jsp

------------------------------------------------------------------------------------------------------------------------------------

index.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1 align="center">MVC model2 방식을 이용한 회원 로그인</h1>
    <h3 align="center"><a href="views/member/loginForm.jsp">회원 서비스 테스트</a></h3>
</body>
</html>





loginForm.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
    input[type='submit'] {
        height:55px;
    }
</style>
</head>
<body>
    <div align="center">
        <h2>로그인 테스트</h2>
        <form action="<%=request.getContextPath() %>/login" method="post">
            <table>
                <tr>
                    <td><label>아이디</label></td>
                    <td><input type="text" name="userId"></td>
                    <td rowspan="2"><input type="submit" value="로그인"></td>
                </tr>
                <tr>
                    <td><label>비밀번호</label></td>
                    <td><input type="password" name="password"></td>
                </tr>
                <tr>
                    <td colspan="3"><input type="button" onclick="location.href='newAccount.jsp'" value="회원가입"></td>
                </tr>
            </table>
        </form>
       
    </div>
</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------


로그인 기능구현 MemberService.java는 멤버 추가도 포함되어 있다.


LoginServlet.java, MemberService.java, MemberDao.java

------------------------------------------------------------------------------------------------------------------------------------

LoginServlet.java



package com.kh.w6.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 javax.servlet.http.HttpSession;

import com.kh.w6.member.model.service.MemberService;
import com.kh.w6.member.model.vo.Member;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
   
    // 로그인처리를 위한 상수 선언
    public static int LOGIN_OK = 1;
    public static int WRONG_PASSWORD = 0;
    public static int ID_NOT_EXIST = -1;
   
    public LoginServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 전송값에 한글이 있는 경우
        request.setCharacterEncoding("UTF-8");
       
        // 2. 전송값 꺼내서 변수에 기록하기
        String userId = request.getParameter("userId");
        String password = request.getParameter("password");
       
        System.out.println("ID : " + userId);
        System.out.println("Pwd : " + password);
       
        //3. 비지니스 로직을 처리할 서비스 클래스의 메소드로 전달값 넘김
        Member requestMember = new Member();
        requestMember.setUserId(userId);
        requestMember.setPassword(password);
               
        Member loginUser = new MemberService().loginCheck(requestMember);
       
        //4. 받은 결과에 따라서 성공/실패 페이지 내보내기
            String view = "";
           
            if(loginUser.getStatus() == LOGIN_OK) {
                view = "views/main/main.jsp";
               
                HttpSession session = request.getSession();
               
                session.setAttribute("loginUser",  loginUser);
               
            }else {
                String msg;
               
                if(loginUser.getStatus() == WRONG_PASSWORD) {
                    msg = "패스워드를 잘못 입력하셨습니다.";
                }else {
                    msg = "존재하지 않는 아이디입니다.";
                }
               
                request.setAttribute("msg", msg);
               
                view = "views/common/errorPage.jsp";
               
            }
           
           
            RequestDispatcher reqDispatcher = request.getRequestDispatcher(view);
            reqDispatcher.forward(request, response);
    }

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

}







MemberService.java



package com.kh.w6.member.model.service;

import java.sql.Connection;
import java.sql.SQLException;

import static com.kh.w6.common.JDBCTemplate.*;

import com.kh.w6.member.controller.LoginServlet;
import com.kh.w6.member.model.dao.MemberDao;
import com.kh.w6.member.model.vo.Member;

public class MemberService {
    //로그인 처리용 메소드
    public Member loginCheck(Member requestMember) {
        Connection con = getConnection();
       
        MemberDao mDao = new MemberDao();
       
        int result = mDao.checkStatus(con, requestMember);
       
        Member loginUser = new Member();
        if(result == LoginServlet.LOGIN_OK) { // 로그인 성공
            loginUser = mDao.selectOne(con, requestMember);
            loginUser.setStatus(LoginServlet.LOGIN_OK);
        }else {
            if (result == LoginServlet.WRONG_PASSWORD) { // 비밀번호 틀림
                loginUser.setStatus(LoginServlet.WRONG_PASSWORD);
            }else { // 아이디 틀림
                loginUser.setStatus(LoginServlet.ID_NOT_EXIST);
            }
        }   
       
        return loginUser;
    }
   
    // 회원 추가용 메소드
    public int addMember(Member newMember) {
        Connection con = getConnection();
       
        MemberDao mDao = new MemberDao();
       
        int result = mDao.updateMember(con, newMember);

        try {
            if(result > 0){
                con.commit();
            }else{
                con.rollback();
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        return result;
    }
}








MemberDao.java



package com.kh.w6.member.model.dao;

import java.io.FileReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import com.kh.w6.member.controller.LoginServlet;
import com.kh.w6.member.model.vo.Member;
import static com.kh.w6.common.JDBCTemplate.*;

public class MemberDao {
    private Properties prop = new Properties();
   
    public MemberDao() {
        String fileName = MemberDao.class.getResource("/sql/member/member-query.properties").getPath();
   
        try {
            prop.load(new FileReader(fileName));
        } catch (Exception e) {
            e.printStackTrace();
        }
       
    }
   
    // 로그인 상태 조회용 메소드
    public int checkStatus(Connection con, Member requestMember) {
        PreparedStatement pstmt = null;
        int result = LoginServlet.ID_NOT_EXIST; // 실패했을 때를 위한 초기화
        ResultSet rset = null;
       
        String query = prop.getProperty("checkStatus");
       
        try {
            pstmt = con.prepareStatement(query);
            pstmt.setString(1, requestMember.getUserId());
           
            rset = pstmt.executeQuery();
           
            String userId = "";
            String password = "";
           
            if (rset.next()) {
                userId = rset.getString("USER_ID");
                password = rset.getString("PASSWORD");
               
            }
           
            if (requestMember.getUserId().equals(userId) && requestMember.getPassword().equals(password)) {
                result = LoginServlet.LOGIN_OK;
            }else if (requestMember.getUserId().getClass().equals(userId) && !requestMember.getPassword().equals(password)) {
                result = LoginServlet.WRONG_PASSWORD;
            }else {
                result = LoginServlet.ID_NOT_EXIST;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rset);
            close(pstmt);
        }
       
       
        return result;
    }

    // 로그인 정보 조회용 메소드
    public Member selectOne(Connection con, Member requestMember) {
        Member loginUser = null;
        PreparedStatement pstmt = null;
        ResultSet rset = null;
       
        String query = prop.getProperty("selectOne");
       
       
        try {
            pstmt = con.prepareStatement(query);
            pstmt.setString(1, requestMember.getUserId());
            pstmt.setString(2, requestMember.getPassword());
           
           
            rset = pstmt.executeQuery();
           
            if (rset.next()) {
                loginUser = new Member();
               
                loginUser.setUserId(rset.getString("USER_ID"));
                loginUser.setPassword(rset.getString("PASSWORD"));
                loginUser.setUserName(rset.getString("USER_NAME"));
                loginUser.setGender(rset.getString("GENDER"));
                loginUser.setAge(rset.getInt("AGE"));
                loginUser.setEmail(rset.getString("EMAIL"));
                loginUser.setPhone(rset.getString("PHONE"));
                loginUser.setAddress(rset.getString("ADDRESS"));
                loginUser.setHobby(rset.getString("HOBBY"));
                loginUser.setEnrollDate(rset.getDate("ENROLL_DATE"));
               
               
               
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(rset);
            close(pstmt);
        }
       
       
        return loginUser;
    }

    public int updateMember(Connection con, Member newMember) {
        PreparedStatement pstmt = null;
        int result = 0;
        String query = prop.getProperty("updateOne");
       
        try {
            pstmt = con.prepareStatement(query);
           
            pstmt.setString(1, newMember.getUserId());
            pstmt.setString(2, newMember.getPassword());
            pstmt.setString(3, newMember.getUserName());
            pstmt.setString(4, newMember.getGender());
            pstmt.setInt(5, newMember.getAge());
            pstmt.setString(6, newMember.getEmail());
            pstmt.setString(7, newMember.getPhone());
            pstmt.setString(8, newMember.getAddress());
            pstmt.setString(9, newMember.getHobby());
           
            result = pstmt.executeUpdate();
           
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(pstmt);
        }

       
        return result;
    }

}

------------------------------------------------------------------------------------------------------------------------------------



driver.properties, member-query.properties

------------------------------------------------------------------------------------------------------------------------------------

driver.properties



driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=jsp
password=jsp






member-query.properties



checkStatus=SELECT * FROM member WHERE user_id = ?
selectOne=SELECT * FROM member WHERE user_id = ? AND password = ?
updateOne=INSERT INTO MEMBER VALUES(?,?,?,?,?,?,?,?,?,SYSDATE)

------------------------------------------------------------------------------------------------------------------------------------



멤버의 정보가 담길 객체



Member.java

------------------------------------------------------------------------------------------------------------------------------------

package com.kh.w6.member.model.vo;

import java.sql.Date;

public class Member implements java.io.Serializable{
    private String userId;
    private String password;
    private String userName;
    private String gender;
    private int age;
    private String email;
    private String phone;
    private String address;
    private String hobby;
    private Date enrollDate;
    private int status = 99; // 1또는 0으로 로그인 성공 실패를 가리기 때문에 쓰레기값을 넣어놓는다.
   
    public Member() {}

    public Member(String userId, String password, String userName, String gender, int age, String email, String phone,
            String address, String hobby, Date enrollDate, int status) {
        super();
        this.userId = userId;
        this.password = password;
        this.userName = userName;
        this.gender = gender;
        this.age = age;
        this.email = email;
        this.phone = phone;
        this.address = address;
        this.hobby = hobby;
        this.enrollDate = enrollDate;
        this.status = status;
    }

    public Member(String userId, String password, String userName, String gender, int age, String email, String phone,
            String address, String hobby) {
        super();
        this.userId = userId;
        this.password = password;
        this.userName = userName;
        this.gender = gender;
        this.age = age;
        this.email = email;
        this.phone = phone;
        this.address = address;
        this.hobby = hobby;
    }
   
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return super.toString();
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public Date getEnrollDate() {
        return enrollDate;
    }

    public void setEnrollDate(Date enrollDate) {
        this.enrollDate = enrollDate;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }
   
   
   
}

------------------------------------------------------------------------------------------------------------------------------------




로그아웃, 회원가입


LogoutServlet.java, newAccount.java

------------------------------------------------------------------------------------------------------------------------------------

LogoutServlet.java



package com.kh.w6.member.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LogoutServlet
 */
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
      
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LogoutServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.getSession().invalidate();
       
        response.sendRedirect("views/member/loginForm.jsp");
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}



newAccount.java



package com.kh.w6.member.controller;

import java.io.IOException;
import java.io.PrintWriter;

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.w6.member.model.service.MemberService;
import com.kh.w6.member.model.vo.Member;

@WebServlet("/newaccount")
public class newAccount extends HttpServlet {
    private static final long serialVersionUID = 1L;
      
    public newAccount() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
       
        String userId = request.getParameter("userId");
        String password = request.getParameter("password");
        String userName = request.getParameter("userName");
        int age = Integer.parseInt(request.getParameter("age"));
        String gender = request.getParameter("gender");
        String email = request.getParameter("email");
        String phone = request.getParameter("phone");
        String address = request.getParameter("address");
        String[] hobbies = request.getParameterValues("hobby");
       
        String hobby = String.join(",", hobbies);
       
        System.out.println("입력한 정보----------\r\n"
                + userId + "\r\n"
                + password + "\r\n"
                + userName + "\r\n"
                + age + "\r\n"
                + gender + "\r\n"
                + email + "\r\n"
                + phone + "\r\n"
                + address + "\r\n"
                + hobby);
       
        Member newMember = new Member(userId, password, userName, gender, age, email, phone, address, hobby);
       
        System.out.println(newMember.toString());
       
        int result = new MemberService().addMember(newMember);
       
        response.setContentType("text/html; charset=UTF-8");
        PrintWriter out = response.getWriter();
       
        if(result > 0){
            out.println("<script>alert('성공적으로 회원 가입 되었습니다.');</script>");
            out.println("<script>location.href='views/member/loginForm.jsp';</script>");
            out.close();
           
        }else{
            out.println("<script>alert('회원 가입에 실패했습니다.');</script>");
            out.println("<script>history.back();</script>");
            out.close();
           
        }

    }

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

}

------------------------------------------------------------------------------------------------------------------------------------




JDBCTemplate.java

------------------------------------------------------------------------------------------------------------------------------------

JDBCTemplate.java



package com.kh.w6.common;

import java.io.FileReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCTemplate {
    public static Connection getConnection() {
        Connection conn = null;
        Properties prop = new Properties();
       
        String fileName = JDBCTemplate.class.getResource("/sql/driver.properties").getPath();
               
        System.out.println(fileName);
       
        try {
            prop.load(new FileReader(fileName));
            String driver = prop.getProperty("driver");
            String url = prop.getProperty("url");
            String user = prop.getProperty("user");
            String password = prop.getProperty("password");
           
            // 아래 클래스 구문은 신버전에서는 자동으로 추가되어서 생략해도 되지만
            // 구버전 호환을 위해 명시해두자.
            Class.forName(driver);
           
            conn = DriverManager.getConnection(url, user, password);
           
            conn.setAutoCommit(false);
           
            System.out.println(conn);
           
        } catch (Exception e) {
            e.printStackTrace();
        }
        // prop 파일을 수정할 때 classes 폴더 아래의 파일을 수정하면 서버 껏따 킬때 재생성 되기 때문에 사라진다.
        // 그리고 바로바로 수정사항이 적용이 안될 때도 있는데 메뉴바 상단의 Project - clean을 실행하면 강제 재컴파일 시켜준다.
       
        return conn;
    }
   
    public static void close(Connection con) {
        try {
            if(con != null && !con.isClosed()) {
                con.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void close(Statement stmt) {
        try {
            if(stmt != null && !stmt.isClosed()) {
                stmt.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void close(ResultSet rset) {
        try {
            if(rset != null && !rset.isClosed()) {
                rset.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void commit(Connection con) {
        try {
            if(con != null && !con.isClosed()) {
                con.commit();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
    public static void rollback(Connection con) {
        try {
            if(con != null && !con.isClosed()) {
                con.rollback();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

------------------------------------------------------------------------------------------------------------------------------------





이 외의 폼들은 다음과 같다.


main.jsp, newAccount.jsp, errorPage.jsp

------------------------------------------------------------------------------------------------------------------------------------

main.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.kh.w6.member.model.vo.Member"%>
<% Member loginUser = (Member)session.getAttribute("loginUser"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
    #userInfo {
        float:right;
    }
</style>
</head>
<body>
    <h1 align="center">Welcome to MVC 랜드</h1>
    <div id="userInfo">
        <label><%= loginUser.getUserName() %>님 환영합니다.</label><br>
        <button id="changeInfo">정보수정</button>
        <button id="logout">로그아웃</button>
    </div>
    <script type="text/javascript">
        $(function name() {
            $("#logout").click(function() {
                location.href="<%=request.getContextPath()%>/logout";
            });
        });
    </script>
</body>
</html>





newAccount.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="<%=request.getContextPath() %>/newaccount" method="post">
        <input type="text" placeholder="아이디" name="userId" id="userId">
        <br>
        <input type="password" placeholder="패스워드" name="password" id="password">
        <br>
        <input type="text" placeholder="이름" name="userName" id="userName">
        <br>
        <input type="text" placeholder="나이" name="age" id="age">
        <br>
        <input type="email" placeholder="이메일" name="email" id="email">
        <br>
        <input type="tel" placeholder="휴대폰" name="phone" id="phone">
        <br>
        <input type="text" placeholder="주소" name="address" id="address">
        <br>
        <label>성별 : </label>
        <input type="radio" name="gender" id="male" value="M">
        <label for="male">남</label>
        <input type="radio" name="gender" id="female" value="F">
        <label for="female">여</label>
        <br>
        <label>취미 : </label>
        <input type="checkbox" name="hobby" id="hobby0" value="운동">
        <label for="hobby0">운동</label>
        <input type="checkbox" name="hobby" id="hobby1" value="등산">
        <label for="hobby1">등산</label>
        <input type="checkbox" name="hobby" id="hobby2" value="독서">
        <label for="hobby2">독서</label>
        <input type="checkbox" name="hobby" id="hobby3" value="게임">
        <label for="hobby3">게임</label>
        <input type="checkbox" name="hobby" id="hobby4" value="여행">
        <label for="hobby4">여행</label>
        <br><br>
        <input type="submit" value="가입">&nbsp;&nbsp;
        <input type="reset" value="취소">
    </form>
</body>
</html>






errorPage.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% String msg = (String)request.getAttribute("msg"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1><%= msg %></h1>
</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------











MemberException.java 파일은 따로 내용을 수정 안하였으니 만들 내용이 없다.





MVC 패턴이란 Model, View, Controller의 구조로 이루어진걸 말한다.


Run에서 Main 스레드에 의해 프로그램이 실행되고


View를 통해서 화면을 보여주고


Controller에서 사용자가 이용할 기능들을 view와 연결한다.


Model은 Controller에서 사용할 객체와 같은 모델들을 사용하게 된다.


모델에서는 DB와의 통신을 통해 조회, 수정 등 SQL문을 사용한다.




MVC 2 패턴에서는


Controller와 Model 사이에 공통적으로 사용할 기능(DB연결이나 기능) Common이 추가된다.





이 후의 예제는 위와 같은 구조로 작성된다.



이번 폴더구조는 다음과 같다.




이미지 파일 첨부


images.zip





이번에는 JSP 프로젝트에 JDBC 기능을 사용한다.


WEB-INF 폴더 아래에 lib 폴더를 만들고


ojdbc6.jar을 복사하자.(JDBC 할 때 build Path 추가와 같은 작업)


이 파일은 jdbc를 공부할 때 어디있는지 한번 설명을 했었다. (https://qdgbjsdnb.tistory.com/196?category=726465)


위의 글 설명 그대로


sql을 사용하기 위한 Library 파일을 불러온다.


계속 사용했던 oracle에 설치 폴더에 있는 파일을 불러온다.


경로는 설치 경로 + oraclexe/app/oracle/product/11.2.0/server/jdbc/lib 에 ojdbc6이라는 파일이 존재한다.



출처: https://qdgbjsdnb.tistory.com/196?category=726465 [하위^^]

sql을 사용하기 위한 Library 파일을 불러온다.


계속 사용했던 oracle에 설치 폴더에 있는 파일을 불러온다.


경로는 설치 경로 + oraclexe/app/oracle/product/11.2.0/server/jdbc/lib 에 ojdbc6이라는 파일이 존재한다.



출처: https://qdgbjsdnb.tistory.com/196?category=726465 [하위^^]

sql을 사용하기 위한 Library 파일을 불러온다.


계속 사용했던 oracle에 설치 폴더에 있는 파일을 불러온다.


경로는 설치 경로 + oraclexe/app/oracle/product/11.2.0/server/jdbc/lib 에 ojdbc6이라는 파일이 존재한다.



출처: https://qdgbjsdnb.tistory.com/196?category=726465 [하위^^]으

sql을 사용하기 위한 Library 파일을 불러온다.


계속 사용했던 oracle에 설치 폴더에 있는 파일을 불러온다.


경로는 오라클 설치 경로 + oraclexe/app/oracle/product/11.2.0/server/jdbc/lib 에 ojdbc6이라는 파일이 존재한다.




파일을 찾아서 lib 폴더에 복사하면 된다.







01_testPerson.jsp는 선호도 조사로 선택한 항목, 입력 값 등을 통해서


해당하는 이미지를 출력한다.


또한 선택을 안했을 경우의 예외처리도 전부 JSP 파일에서 구현한다.





02_memberJoin.jsp는 JSP에서 데이터 베이스에 접근하여 새로운 정보를 추가하여 회원가입을 구현한다.



index.jsp

------------------------------------------------------------------------------------------------------------------------------------

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>MVC Model1</h1>
    <p>jsp도 서블릿이다!</p>
    <h3><a href="views/01_testPerson.jsp">선호도 조사</a></h3>
    <h3><a href="views/02_memberJoin.jsp">회원가입</a></h3>
</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------


01_testPerson.jsp, 01_testPersonResult.jsp

------------------------------------------------------------------------------------------------------------------------------------

01_testPerson.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h2>개인 취향 테스트(MVC)</h2>
    당신의 취향을 테스트합니다.<br>
    데이터 입력 후 확인 버튼을 누르세요
   
    <form action="01_testPersonResult.jsp" name="personFrm" method="post">
        <ul style="list-style: none; line-height: 200%;">
            <li>이름은? <input type="text" name="name" size="10"></li>
            <li> 좋아하는 색?
                <input type="radio" name="color" id="color-red" value="빨강">
                <label for="color-red">빨강</label>
                <input type="radio" name="color" id="color-blue" value="파랑">
                <label for="color-blue">파랑</label>
                <input type="radio" name="color" id="color-yellow" value="노랑">
                <label for="color-yellow">빨강</label>
            </li>
            <li>좋아하는 동물?
                <select name="animal" id="animal">
                    <option value="강아지">강아지</option>
                    <option value="고양이">고양이</option>
                    <option value="금붕어">금붕어</option>
                </select>
            </li>
            <li>좋아하는 음식?(모두 고르세요)
                <input type="checkbox" name="food" id="food1" value="짜장면">
                <label for="food1">짜장면</label>
                <input type="checkbox" name="food" id="food2" value="짬뽕">
                <label for="food2">짬뽕</label>
                <input type="checkbox" name="food" id="food3" value="탕수육">
                <label for="food3">탕수육</label>
                <input type="checkbox" name="food" id="food4" value="양장피">
                <label for="food4">양장피</label>
                <input type="checkbox" name="food" id="food5" value="팔보채">
                <label for="food5">팔보채</label>
            </li>
            <li>
                <br>
                <input type="submit" value="확인">&nbsp;&nbsp;
                <input type="reset" value="취소">
            </li>
        </ul>
    </form>
   
</body>
</html>






01_testPersonResult.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    //1.전달 파라미터 한글 처리
    request.setCharacterEncoding("utf-8");

    //2.전달된 파라미터 변수에 담기
    String name = request.getParameter("name");
    String color = request.getParameter("color");
    String animal = request.getParameter("animal");
    String[] foodArr = request.getParameterValues("food");
   
   
   
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
    <div id="container">
        <div id="header">
            <h2><span style="color: blue;"><%= name %></span>님의 개인 취향 테스트</h2>
        </div>
        <div id="color">
            <span class="title">당신이 좋아하는 색깔은?</span>
        </div>
       
        <div id="animal">
            <span class="title">당신이 좋아하는 동물은?</span>
        </div>
        <div id="food">
            <span class="title">당신이 좋아하는 음식은?</span>
        </div>
   
    </div>
    <script>
        $(function(){
            <%
                if(color != null){
                switch(color){
                    case "빨강" :
            %>
                            $("#color").append("<img src='<%=request.getContextPath()%>/images/red.png'>");
            <%                break;
                    case "파랑" :
            %>
                            $("#color").append("<img src='<%=request.getContextPath()%>/images/blue.png'>");
            <%                break;
                    case "노랑" :
            %>
                            $("#color").append("<img src='<%=request.getContextPath()%>/images/blue.png'>");
            <%                break;
                }
                }else{
            %>
                    $("#color").append("선택한 색깔이 없습니다 ㅜㅜ");
            <%
                }
            %>
        });
    </script>
    <script>
        $(function(){
            <%
                switch(animal){
                    case "강아지" :
            %>
                            $("#animal").append("<img src='<%=request.getContextPath()%>/images/dog.png'>");
            <%                break;
                    case "고양이" :
            %>
                            $("#animal").append("<img src='<%=request.getContextPath()%>/images/cat.png'>");
            <%                break;
                    case "금붕어" :
            %>
                            $("#animal").append("<img src='<%=request.getContextPath()%>/images/fish.png'>");
            <%                break;
                }
            %>
        });
    </script>
    <script>
        $(function(){
            <%
                try{
                for(int i = 0; i < foodArr.length; i++){   
                    switch(foodArr[i]){
                        case "짜장면" :
            %>
                            $("#food").append("<img src='<%=request.getContextPath()%>/images/jjm.png'>");
            <%
                            break;
                        case "짬뽕" :
            %>
                            $("#food").append("<img src='<%=request.getContextPath()%>/images/jjbong.png'>");
            <%
                            break;
                        case "탕수육" :
            %>
                            $("#food").append("<img src='<%=request.getContextPath()%>/images/tangsy.png'>");
            <%
                            break;
                        case "양장피" :
            %>
                            $("#food").append("<img src='<%=request.getContextPath()%>/images/yang.png'>");
            <%
                            break;
                        case "팔보채" :
            %>
                            $("#food").append("<img src='<%=request.getContextPath()%>/images/palbc.png'>");
            <%
                            break;
                    }   
                }
                }catch(Exception e){
            %>
                            $("#food").append("선택한 음식이 없습니다 ㅜㅜ");
            <%
                }
            %>
        });
    </script>
</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------





02_memberJoin.jsp, 02_memberJoinResult.jsp

------------------------------------------------------------------------------------------------------------------------------------

02_memberJoin.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <div align="center">
        <h2>회원 가입 정보 입력</h2>
        <br>
        <form action="02_memberJoinResult.jsp" method="post">
            <input type="text" placeholder="아이디" name="userId" id="userId">
            <br>
            <input type="password" placeholder="패스워드" name="password" id="password">
            <br>
            <input type="text" placeholder="이름" name="userName" id="userName">
            <br>
            <input type="text" placeholder="나이" name="age" id="age">
            <br>
            <input type="email" placeholder="이메일" name="email" id="email">
            <br>
            <input type="tel" placeholder="휴대폰" name="phone" id="phone">
            <br>
            <input type="text" placeholder="주소" name="address" id="address">
            <br>
            <label>성별 : </label>
            <input type="radio" name="gender" id="male" value="M">
            <label for="male">남</label>
            <input type="radio" name="gender" id="female" value="F">
            <label for="female">여</label>
            <br>
            <label>취미 : </label>
            <input type="checkbox" name="hobby" id="hobby0" value="운동">
            <label for="hobby0">운동</label>
            <input type="checkbox" name="hobby" id="hobby1" value="등산">
            <label for="hobby1">등산</label>
            <input type="checkbox" name="hobby" id="hobby2" value="독서">
            <label for="hobby2">독서</label>
            <input type="checkbox" name="hobby" id="hobby3" value="게임">
            <label for="hobby3">게임</label>
            <input type="checkbox" name="hobby" id="hobby4" value="여행">
            <label for="hobby4">여행</label>
            <br><br>
            <input type="submit" value="가입">&nbsp;&nbsp;
            <input type="reset" value="취소">
        </form>
    </div>


</body>
</html>





02_memberJoinResult.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.sql.*"%>
<%
    //1.한글 인코딩 처리
    request.setCharacterEncoding("utf-8");

    //2.전송값 꺼내서 변수에 기록
    String userId = request.getParameter("userId");
    String password = request.getParameter("password");
    String userName = request.getParameter("userName");
    int age = Integer.parseInt(request.getParameter("age"));
    String gender = request.getParameter("gender");
    String email = request.getParameter("email");
    String phone = request.getParameter("phone");
    String address = request.getParameter("address");
   
    String[] hobbies = request.getParameterValues("hobby");
   
    //String[]을 구분자로 연결하는 String의 스태틱메소드 join
    String hobby = String.join(",", hobbies);
   
    //3.비즈니스로직 작성
    Connection conn = null;
    PreparedStatement pstmt = null;
    int result = 0;
    String msg = "";
   
    String query = "INSERT INTO MEMBER VALUES(?,?,?,?,?,?,?,?,?,SYSDATE)";
   
    try{
        Class.forName("oracle.jdbc.driver.OracleDriver");
       
        conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "jsp", "jsp");
       
        pstmt = conn.prepareStatement(query);
        pstmt.setString(1, userId);
        pstmt.setString(2, password);
        pstmt.setString(3, userName);
        pstmt.setString(4, gender);
        pstmt.setInt(5, age);
        pstmt.setString(6, email);
        pstmt.setString(7, phone);
        pstmt.setString(8, address);
        pstmt.setString(9, hobby);
       
        result = pstmt.executeUpdate();
       
        if(result > 0){
            conn.commit();
            msg = "성공적으로 회원 가입 되었습니다.";
        }else{
            conn.rollback();
            msg = "회원 가입에 실패했습니다.";
        }
       
       
    }catch(Exception e){
        e.printStackTrace();
    }finally {
        try{
            pstmt.close();
            conn.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
   
   
   
   
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <ul style="list-style: none; line-height: 200%">
        <li>아이디 : <%= userId %></li>
        <li>패스워드 : <%= password %></li>
        <li>이름 : <%= userName %></li>
        <li>나이 : <%= age %></li>
        <li>이메일 : <%= email %></li>
        <li>성별
            <span id="gender" style="font-weight: bold;
            color: <%
                    String genderColor = "";
                    if("M".equals(gender)){
                        genderColor = "blue";
                    }else{
                        genderColor = "red";
                    }
                %><%=genderColor%>"><%=gender %></span>
        </li>
        <li>휴대폰 : <%= phone %></li>
        <li>주소 : <%= address %></li>
        <li>취미 : <%= hobby %></li>
   
    </ul>
    <hr>
    <p><%= msg %></p>


</body>
</html>

------------------------------------------------------------------------------------------------------------------------------------





주목해야 할 점은 html문 중간중간에 <%%>를 사용하여 연산된 데이터를 표현하는 것


또한 Jquery 문에도 조건문과 섞어서 사용하는 방법을 주목하자.












이번 예는 간단한 JSP 기능들을 이용한 페이지들을 사용해보자.


테이블 구조는 다음과 같다.







총 4가지의 페이지를 볼 수 있는데 01_sum은 연산의 결과가 오류일 때 정해진 오류 페이지를 보여준다.


페이지를 열 때 브라우저에 400번대 에러와 500번대 에러는 흔히 볼 수 있는데


500번대 에러는 서버측의 에러이기 때문에 해커가 현재 서버가 어떤 문제가 있는지 코드에 어떤 오류가 있는지


알 수 있기 때문에 500번 오류는 노출하지 않는걸 권장한다.




두번째로 02_date인데 웹브라우저에서 자주 사용하는 날짜 함수를 JSP에서 어떻게 사용하는지 확인해보자.



세번째로 03_fortune은 다른 페이지(jsp 파일)를 불러와 현재 페이지에 포함(include)하는 방법을 확인해보자



네번째 04_menu는 간단하게 get방식으로 값을 넘겨서 연산처리를 하여 결과를 확인해보자.






index.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>JSP 테스트</h1>
    <h3><a href="views/01_sum.jsp">테스트1</a></h3>
    <h3><a href="views/02_date.jsp">테스트2</a></h3>
    <h3><a href="views/03_fortune.jsp">테스트3</a></h3>
    <h3><a href="views/04_menu.jsp">테스트4</a></h3>
</body>
</html>










01_sum.jsp




<%-- directive page : 페이지 지시자 태그'<%@' --%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%--
        아래의 코드(System.out.println)를 보면 에러가 발생하는 구문이다.
        실행하면 에러페이지에 아래 코드가 출력이 되는데 코드가 그대로 노출되기 때문에 보안에 매우 취약하다.
        따라서 에러 페이지를 따로 지정하면 된다.
    --%>
    <%@ page errorPage="errorPage.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<%-- JSP는 동적 컴파일을 지원하기 때문에 변경사항이 있어도 서버를 껏다 킬 필요가 없다. --%>
<body>
    <%-- JSP 주석 '<%--' --%>
    <!-- HTML 주석 -->
   
   
   
    <%-- Scripting Element 1 : scriptlet --%>
    <%-- <%로 시작해서 %>로 끝나는 것을 스크립틀릿이라고 부른다. --%>
    <%
        int total = 0;
       
        for(int i = 1; i <= 10; i++){
            total += i;
        }
       
        // 아래의 코드를 보면 에러가 발생하는 구문이다.
        // 실행하면 에러페이지에 아래 코드가 출력이 되는데
        String s = null;
        System.out.println(s.charAt(0));
    %>
   
   
   
    <%-- Scripting element 2 : expression 기능은 자바 코드에서 작성한 결과값을 출력한다. --%>
    <%-- expression 태그는 세미콜론이 있으면 에러가 난다. --%>
    <h4>1부터 10까지의 합은 : <span style="color: red; font-size: 16pt; "><%= total %></span></h4>
    <h4>1부터 10까지의 합은 : <span style="color: red; font-size: 16pt; "><% out.println(total); %></span></h4>
    <%-- out은 선언하지 않았는데 사용할 수 있음 - 내장객체이므로 가능 --%>
</body>
</html>





errorPage.jsp



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>에러페이지</h1>
    <h3>에러 종류 : <%= exception.getClass().getName() %></h3>
</body>
</html>











02_date.jsp




<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <%
        Date now = new Date();
       
        String date = String.format("%tF", now);
        String time = String.format("%tp %tT", now, now);
        String today = String.format("%tY년 %tm월, %td일, %tA", now, now, now, now);
       
        /*
        날짜 타입           설명
        ------------------------------------------
        %tF          날짜를 yyyy-mm-dd 형식으로 포맷
        %tT          날짜의 시각을 HH:MM:SS 형식으로 포맷
        ------------------------------------------
        %tY          4자리 년도만 출력
        %ty          2자리 년도만 출력
        %tB          월의 이름 영문(January, Febuary, ....)
        %tm          월을 숫자로 (01, 02, 03 ~ 12)
        %td          일수를 1 ~ 31로 표현
        %te          %td와 같다.
        %tA          요일명 출력
        ------------------------------------------
        %tp          오전, 오후 출력
        %tk          시간을 0 ~ 23 으로 출력
        %tl          시간을 1 ~ 12로 출력
        %tM          분을 00 ~ 59로 출력
        %tS          초를 00 ~ 59로 출력
        ------------------------------------------
        */
    %>
   
    <ul style="list-style: decimal;">
        <li>오늘의 날짜 : <%= date %></li>
        <li>현재 시간 : <%= time %></li>
        <li>오늘은 <span style="color: red;"><%= today %></span>입니다.</li>
       
    </ul>
</body>
</html>










03_fortune.jsp



<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%--
<%
    Date now = new Date();
    String today = String.format("%tY년 %tm월 %td일 %tA", now, now, now, now);
%>
--%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <%-- <h2>오늘의 운세<sub style="color:lightgray"><%= today %></sub></h2> --%>
    <h2>오늘의 운세<%@ include file="today.jsp" %></h2>
    <%-- 위의 date 때문에 오류가 나기 때문에 주석으로 감싼다. --%>
    <select>
        <option>쥐띠</option>
        <option>소띠</option>
        <option>호랑이띠</option>
        <option>토끼띠</option>
        <option>용띠</option>
        <option>뱀띠</option>
        <option>말띠</option>
        <option>양띠</option>
        <option>원숭이띠</option>
        <option>닭띠</option>
        <option>개띠</option>
        <option>돼지띠</option>
    </select>
   
</body>
</html>






today.jsp




<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    Date now = new Date();
    String today = String.format("%tY년 %tm월 %td일 %tA", now, now, now, now);
%>
<%-- include 전용 파일에 HTML 코드들이 있으면 다같이 딸려가기 때문에 지워둔다. iframe과 유사 --%>
<sub style="color: lightgray;"><%= today %></sub>











04_menu.jsp




<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h2>오늘의 메뉴<%@ include file="today.jsp" %></h2>
   
    <!--  13번째 줄과 14번째 줄은 같은 의미 -->
    <!-- <form action="/w4/menu.Order.do" method="get" name="menuFrm"></form> -->
    <form action="<%= request.getContextPath() %>/menuOrder" method="get" name="menuFrm">
        <select id="menu" name="menu">
            <option value="햄버거">햄버거</option>
            <option value="짜장면">짜장면</option>
            <option value="짬뽕">짬뽕</option>
            <option value="순대국">순대국</option>
        </select>
        <input type="submit" value="선택완료">
    </form>
   
</body>
</html>











MenuOrderServlet.java




package com.kh.servletTest.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;

@WebServlet("/menuOrder")
public class MenuOrderServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
      
    public MenuOrderServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 전송값에 한글이 있을 경우 인코딩 처리 해야 함, 그냥 항상 하자
        request.setCharacterEncoding("utf-8");
       
        // 2. 전송갑 꺼내서 변수에 기록하기
        String menu = request.getParameter("menu");
       
        // 3. 비지니스 로직
        int price = 0;
        switch (menu) {
        case "햄버거":
            price = 5000;
            break;
        case "짬뽕":
            price = 4000;
            break;
        case "짜장면":
            price = 4500;
            break;
        case "순대국":
            price = 6000;
            break;
        }
       
        // 4. 실행 결과 처리 및 전송 (박싱이 자동으로 처리됨, 오토 박싱)
        request.setAttribute("menu", menu);
        request.setAttribute("price", price);
       
        RequestDispatcher view = request.getRequestDispatcher("views/04_menuResult.jsp");
       
        view.forward(request, response);
       
       
       
       
    }

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

}










04_menuResult.jsp





<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String menu = (String)request.getAttribute("menu");
    int price = (int)request.getAttribute("price");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h2>감사합니다.</h2>
    주문하신 <%= menu %>의 결제 금액은 <%= price %>원 입니다.
</body>
</html>















번호별로 주목할 점은 위에서 설명한거와 같이 넘버별로 하나씩



01_sum <%@ page errorPage="errorPage.jsp" %>을 통해서 임의의 에러 페이지를 지정하고


errorPage.jsp에서는 <%= exception.getClass().getName() %>을 통해서 에러 코드(널포인터 익셉션)를 표시해준다






02_date는 <%%> 구문안에 Date를 사용하고 사용하기 위해서 상단에 import해야 하는것을 확인하자.


그 외 실제로 확인하는 방법은 주석문에 정리해두었다.






03_fortune은 <%@ include file="today.jsp" %>을 통해서 적절한 부분에 해당 jsp 파일을 불러온다.


불러올 파일의 내용을 전부 가져오기 때문에 HTML 태그라던가 head body 등 쓸모없는 부분은 지워서 작성한다.






네번째 04_menu는 JSP -> Servlet -> JSP 순으로 데이터의 흐름이 어떻게 움직이는지 확인해보자.





1. Tomcat이 페이지의 default 값 파일이 저장되어 있는 위치



톰캣을 이클립스 Server에 연동 시키면 프로젝트 구조에 다음과 같은 Servers라는게 생긴다




이 파일들이 전부 default 값으로 설정 해 둔 정보들이 담겨있는 파일이다.


예를 들어 페이지의 맨 첫번째 페이지를 지금까지 index.html으로 사용했는데


이것은 어디서 결정되는지 궁금했을거다.


이것은 위의 파일들에 담겨있는 정보들에 지정이 전부 되어있다.


또한 프로젝트에서 이 기본 정보들을 변경 할 수 있다.


이 파일들을 복사해서 프로젝트에 붙여넣고 내용을 바꾼다.(파일 이름은 절대 바꾸면 안된다.)


프로젝트에 동일한 이름의 파일이 있다면 톰캣은 default 파일들을 기준으로 잡지 않고


프로젝트에 있는 파일들의 설정을 따른다.





2. java 파일이 서버에 적용되는 원리


위의 사진에서 네모친 web.xml에 java 파일을 서버에 올리는 작업 대상이 될 폴더가 명시되어 있다.






다음과 같이 <context> 부분의 속성에 workDir="원하는 경로"를 입력하면


그 쪽에 java파일들이 컴파일러에 의해 처리가 되어 class 파일로 저장된다.










+ Recent posts