전자정부프레임워크(3.5)에서 websocket 사용하기

다음은 전자정부프레임워크 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