다음은 전자정부프레임워크 3.5에서 웹소켓을 사용하기 위한 절차임
1. 요구사항
1) 전자정부프레임워크 : 3.5
2) 아파치 톰캣 : 7.0.70 이상(너무 버전이 낮아도 웹소켓을 지원안하므로 유의해야 함)
3) spring framework : 4.0.9.RELEASE
– 전자정부 프레임 3.5 버전에서 사용하는 스프링 버전, 더 높일수 있지만 다른 문제 발생할수 있음. 실제로 스프링 4.1에서는
그간 잘 써왔던 jackson의 지원이 중단되어 다른것으로 대체해야 하는등 문제가 발생한다.
4) JDK : 1.7 이상
5) SockJs : 익스플로러 낮은버전도 지원하기 위하여 사용
2. 메이븐 POM에 추가
4.0.9.RELEASE
org.springframework
spring-context
${springframework.version}
org.springframework
spring-core
${springframework.version}
org.springframework
spring-beans
${springframework.version}
org.springframework
spring-web
${springframework.version}
org.springframework
spring-webmvc
${springframework.version}
org.springframework
spring-websocket
${springframework.version}
javax.servlet
javax.servlet-api
3.1.0
provided
javax.websocket
javax.websocket-api
1.0
provided
3. 웹소켓 설정
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSockConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer
{
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry wshrRegistry)
{
// 웹소켓
wshrRegistry.addHandler(monHandler(), "/websocket/monHandler.ws")
.addInterceptors(new MonHandshakeInterceptor());
// SockJs
wshrRegistry.addHandler(monHandler(), "/websocket/monHandler.sockjs")
.addInterceptors(new MonHandshakeInterceptor())
.withSockJS();
}
@Bean
public MonHandler monHandler()
{
return new MonHandler();
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer)
{
configurer.enable();
}
}
4. DispatcherServletInitializer
public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class>[] getRootConfigClasses()
{
return null;
}
@Override
protected Class>[] getServletConfigClasses()
{
return new Class>[] { WebSockConfig.class };
}
@Override
protected String[] getServletMappings()
{
return new String[] { "/" };
//return new String[] {"*.do", "*.json"};
}
@Override
protected void customizeRegistration(Dynamic registration)
{
registration.setInitParameter("dispatchOptionsRequest", "true");
}
}
5. 인터셉터
– 인터셉터를 쓴 이유는 사실 SockJs에서 넘긴 파라미터를 처리하기 위해서이다. 즉 아래와 같이 userId를 넘겼을때
받을수 있는곳은 인터셉터이기 때문이다.
wsSockJs = new SockJS("http://localhost:8080/websocket/monHandler.sockjs?userId=yomile");
public class MonHandshakeInterceptor extends HttpSessionHandshakeInterceptor
{
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map mpAttributes) throws Exception
{
ServletServerHttpRequest sshRequest = (ServletServerHttpRequest)request;
HttpServletRequest hsrRequest = sshRequest.getServletRequest();
String strUserId = hsrRequest.getParameter("userId");
mpAttributes.put("userId", strUserId);
return super.beforeHandshake(request, response, wsHandler, mpAttributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex)
{
super.afterHandshake(request, response, wsHandler, ex);
}
}
6. 웹소켓 핸들러
– 위의 인테셉터에서 mpAttributes에 파라미터값을 다시 넣어주게 되면 아래 웹소켓 핸들러에서는 WebSocketSession의 getAttributes를
이용하여 값을 빼어 낼수 있게 된다. 결국 JavaScript의 Sockjs에서 넣은 파라미터 값이 최종적으로 여기까지 올수 있게 된다.
//@Component
public class MonHandler extends TextWebSocketHandler
{
private static Logger mStatLogger = LoggerFactory.getLogger(MonHandler.class);
private List mLstSession = null;
public MonHandler()
{
mLstSession = new ArrayList();
}
@Override
public void afterConnectionEstablished(WebSocketSession wssSession) throws Exception
{
Map mpParam = wssSession.getAttributes();
String strUserId = (String)mpParam.get("userId");
mStatLogger.debug(" 접속, UserId:"+ strUserId +",SessionId:"+ wssSession.getId() +", 연결 IP:" + wssSession.getRemoteAddress().getHostName() );
mLstSession.add(wssSession);
}
@Override
protected void handleTextMessage(WebSocketSession wssCurSession, TextMessage tmMsg) throws Exception
{
mStatLogger.debug("*MonHandler.handleTextMessage");
mStatLogger.info("{}로 부터 {} 받음", wssCurSession.getId(), tmMsg.getPayload());
MonVO clsMonVO = MonVO.convert(tmMsg.getPayload());
mStatLogger.debug(" -clsMonVO.getTarget():"+ clsMonVO.getTarget());
mStatLogger.debug(" -clsMonVO.getMessage():"+ clsMonVO.getMessage());
Map mpCurParam = wssCurSession.getAttributes();
String strCurUserId = (String)mpCurParam.get("userId");
mStatLogger.debug(" - CurUserId:"+ strCurUserId);
//연결된 모든 클라이언트에게 메시지 전송
for(WebSocketSession wssSession : mLstSession)
{
Map mpParam = wssSession.getAttributes();
String strUserId = (String)mpParam.get("userId");
if(clsMonVO.getTarget().equals(strUserId) == true)
{
// 전송대상한테만 메시지를 보낸다.
wssSession.sendMessage(new TextMessage(clsMonVO.getMessage()));
}
}
}
@Override
public void handleTransportError(WebSocketSession wssSession, Throwable exception) throws Exception
{
mStatLogger.debug("*MonHandler.handleTransportError");
if(wssSession.isOpen() == true) wssSession.close();
mLstSession.remove(wssSession);
}
@Override
public void afterConnectionClosed(WebSocketSession wssSession, CloseStatus status) throws Exception
{
mStatLogger.debug("*MonHandler.afterConnectionClosed");
mStatLogger.info("{} 연결 끊김.", wssSession.getId());
mLstSession.remove(wssSession);
}
}
7. JSP 설정
<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
test