[Java] WebSocket에서 HttpSession을 가져오는 방법
안녕하세요. 명월입니다.
이 글은 WebSocket에서 HttpSession을 가져오는 방법에 대한 글입니다.
예전에 제가 WebSocket에 관한 글을 쓴 적이 있습니다.
링크 - [Java] 웹 소켓 (WebSocket) - broadcast(session 다루기)
간혹 저에게 질문하시는 분들 중에서 WebSocket에서 httpSession 정보를 가져올 수 없냐고하는 질문이 간혹 있어서 정리했습니다.
먼저 WebSocket도 httpprotocol를 사용하기 때문에 WebSocket안에서 httpSession을 가져올 수 있습니다. 근데 이게 처음 접속할 때 handshake를 거치고 그 다음에는 동기식으로 바뀌기 때문에 이 handshake할 때 Map에 다가 WebSocketSession으로 키로 설정해서 HttpSession을 넣고, WebSocket안에서는 WebSocketSession키로 HttpSession를 가져와서 사용하면 됩니다.(ㅎㅎㅎ....)
먼저 HandShake하는 부분의 설정입니다.
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;
public class HttpSessionConfigurator extends Configurator {
public static final String Session = "Session";
public static final String Context = "Context";
// EndPointConfig에 HttpSession과 HttpContext를 넣는다. Request와 Response는 웹 요청, 응답시에만 필요한 데이터이기 때문에 필요없다.
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
// HttpRequest로부터 Session을 받는다.
HttpSession session = (HttpSession) request.getHttpSession();
// HttpSession으로 부터 Context도 받는다.
ServletContext context = session.getServletContext();
config.getUserProperties().put(HttpSessionConfigurator.Session, session);
config.getUserProperties().put(HttpSessionConfigurator.Context, context);
}
}
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
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;
// handshake 설정하기 위한 클래스를 지정한다.
@ServerEndpoint(value = "/websocket", configurator = HttpSessionConfigurator.class)
public class websocket {
private Map<Session, EndpointConfig> configs = Collections.synchronizedMap(new HashMap<>());
// handshake가 끝나면 handleOpen이 호출된다.
@OnOpen
public void handleOpen(Session userSession, EndpointConfig config) {
System.out.println("client is now connected...");
// EndpointConfig의 클래스를 위 맵에 넣는다.
if (!configs.containsKey(userSession)) {
// userSession 클래스는 connection이 될 때마다 인스턴스 생성되는 값이기 때문에 키로서 사용할 수 있다.
configs.put(userSession, config);
}
}
// 클라이언트로 부터 메시지가 오면 handleMessage가 호출 된다.
@OnMessage
public String handleMessage(String message, Session userSession) {
// 위 맵으로 부터 userSession을 키로 EndpointConfig값을 가져온다.
if (configs.containsKey(userSession)) {
EndpointConfig config = configs.get(userSession);
// HttpSessionConfigurator에서 설정한 session값을 가져온다.
HttpSession session = (HttpSession) config.getUserProperties().get(HttpSessionConfigurator.Session);
// Session의 TestSession키로 데이터를 가져온다. (테스트용)
return "Session - " + (String) session.getAttribute("TestSession");
}
return "error";
}
@OnClose
public void handleClose(Session userSession) {
System.out.println("client is now disconnected...");
// 접속이 종료되면 map에서 EndpointConfig를 제거한다.
if (configs.containsKey(userSession)) {
configs.remove(userSession);
}
}
@OnError
public void handleError(Throwable e, Session userSession) {
e.printStackTrace();
}
}
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("/SessionIn")
public class SessionIn extends HttpServlet {
private static final long serialVersionUID = 1L;
public SessionIn() {
super();
}
// 파라미터 param에 값이 넘겨오면 TestSession이름으로 세션에 넣는다.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String param = request.getParameter("param");
if (param == null || param.isEmpty()) {
param = "hello world";
}
request.getSession().setAttribute("TestSession", param);
response.getWriter().append("Session In OK ");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
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("/SessionOut")
public class SessionOut extends HttpServlet {
private static final long serialVersionUID = 1L;
public SessionOut() {
super();
}
// 요청되면 TestSession이름으로 세션을 제거한다.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getSession().setAttribute("TestSession", null);
response.getWriter().append("Session Clear ");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<input onclick="sendMessage()" value="Send" type="button">
<input onclick="disconnect()" value="Disconnect" type="button">
<br />
<textarea id="messageTextArea" rows="10" cols="50" readonly="readonly"></textarea>
<script type="text/javascript">
var webSocket = new WebSocket("ws://localhost:8080/WebSocketSessionShare/websocket");
var messageTextArea = document.getElementById("messageTextArea");
webSocket.onopen = function(message) {
messageTextArea.value += "Server connect...\n";
};
webSocket.onclose = function(message) {
messageTextArea.value += "Server Disconnect...\n";
};
webSocket.onerror = function(message) {
messageTextArea.value += "error...\n";
};
// 서버로부터 데이터가 오면 Textarea에 표시합니다.
webSocket.onmessage = function(message) {
messageTextArea.value += "Recieve From Server => " + message.data+ "\n";
};
//Send 버튼을 누르면 세션을 가져옵니다.
function sendMessage() {
messageTextArea.value += "Get Http Session!!";
webSocket.send("Get");
}
function disconnect() {
webSocket.close();
}
</script>
</body>
</html>
기본적인 WebSocket의 값은 이전에 작성한 WebSocket예제와 거의 동일합니다.
거기에서 HttpSessionConfigurator클래스가 추가되어서 handshake부분에서 session을 가져오는 부분과 websocket 클래스에서 각 socketSession별로 httpSession을 map에 넣어 사용하는 부분이 추가되었습니다.
먼저 index.jsp로 접속을 합니다.
「./SessionIn?param=데이터」를 통해서 세션에 값을 넣습니다.
다시 index.jsp로 돌아와서 send버튼을 누르면 전에 session에 넣었던 값이 나올 것입니다.
이번에는 「./SessionOut」를 통해서 세션 값을 초기화합니다.
다시 index.jsp로 돌아와서 send버튼을 누르면 Session값이 초기화 되었기 때문에 null나오는 것을 확인할 수 있습니다.
첨부 파일 - WebSocketSessionShare.zip
여기까지 WebSocket에서 HttpSession을 가져오는 방법에 대한 설명이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.