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 통신을 이용하면 된다.


+ Recent posts