Websocket實現前后台通信,demo小測試


  新需求大概如下:用戶登錄系統,登錄成功之后建立websocket連接,實現通信

  總體思路:前端不是我負責,只是簡單的做個功能,先實現登錄,把用戶標識存入HttpSeesion,再建立websocket連接,攔截器HandshakeInterceptor攔截請求,把用戶標識存入Map<String, Object> attributes,然后處理器handler處理各種操作。

/** 
 * @author wangqq 
 * @version 創建時間:2018年11月1日 下午2:59:21 
 * 實現WebSocketConfigure配置自己的socket鏈接
 */
@Configuration //用於定義配置類,可替換xml配置文件
@EnableWebSocket
@EnableWebMvc //啟動Spring MVC特性
public class WebsocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // TODO Auto-generated method stub
        registry.addHandler(handler(), "show").addInterceptors(interceptor()).setAllowedOrigins("*");
    }
    
    @Bean
    public WebSocketHandler handler(){
        return new Hanlder();
    }
    
    @Bean  
    public HandshakeInterceptor interceptor() {  
        return new HandshakeInterceptor();  
    }  

}
registry.addHandler第一個參數是處理器,自己可以寫,第二個參數是前后台建立鏈接的路徑,
addInterceptors 添加攔截,再握手之前之后,處理自己的業務
setAllowedOrigins 解決跨域,*代表不限,如果要指定域名則要http或者https開頭

/** 
 * @author wangqq 
 * @version 創建時間:2018年11月1日 下午3:06:36 
 * 類說明 
 */
public class Hanlder extends TextWebSocketHandler {
    private Logger logger = Logger.getLogger(Hanlder.class);
    private static final Map<Integer,WebSocketSession> hotels;
    
    static{
        hotels = new HashMap<Integer, WebSocketSession>();
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session)
            throws Exception {
        // TODO Auto-generated method stub
        Integer hotelid = IHelper.toInteger(session.getAttributes().get("hotelid"));
        logger.info("-----------------afterConnectionEstablished-----------------");
        if(null != hotelid){
            logger.info(String.format("酒店連接,id:%s", hotelid));
            hotels.put(hotelid, session);
JSONObject json
= new JSONObject(); json.put("code","testMessage"); session.sendMessage(new TextMessage(json.toString())); } //super.afterConnectionEstablished(session); } /** * js調用websocket.send時候,會調用該方法 */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // TODO Auto-generated method stub logger.info(String.format("收到酒店(id:%s)發來消息,消息詳情:%s", session.getAttributes().get("hotelid"),message.toString())); super.handleTextMessage(session, message); //這里可以給用戶發消息 logger.info("執行Hanlder---------客戶端收到請求"); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { // TODO Auto-generated method stub Integer hotelid = IHelper.toInteger(session.getAttributes().get("hotelid")); logger.info(String.format("用戶退出,酒店id:%s", hotelid)); hotels.remove(hotelid); super.afterConnectionClosed(session, status); } /** * 給單個用戶發消息 * @param hotelid * @param message * @throws IOException */ public void sendMessage(Integer hotelid,TextMessage message) throws Exception{ if(hotels.containsKey(hotelid)){ if(hotels.get(hotelid).isOpen()){ hotels.get(hotelid).sendMessage(message); } } } /** * 給所有在線用戶發消息 * @param message * @throws IOException */ public void sendMessage(TextMessage message) throws Exception{ for(Integer id : hotels.keySet()){ WebSocketSession session = hotels.get(id); if(session.isOpen()){ session.sendMessage(message); } } } /** * 多個在線用戶,不同消息 * @param data * @throws Exception */ public void sendMessage(Map<Integer, TextMessage> data) throws Exception{ for(Map.Entry<Integer, TextMessage> entry : data.entrySet()){ Integer hotelid = entry.getKey(); this.sendMessage(hotelid, entry.getValue()); } } /** * 多個用戶,同一消息 * @param hotelids * @param message * @throws Exception */ public void sendMessage(List<Integer> hotelids,TextMessage message) throws Exception{ for(Integer id : hotelids){ this.sendMessage(id, message); } } }
/** 
 * @author wangqq 
 * @version 創建時間:2018年11月2日 下午1:42:00 
 * 類說明 
 */
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
    
    private Logger logger = Logger.getLogger(HandshakeInterceptor.class);
    
    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {
        // TODO Auto-generated method stub
        logger.info("-----------beforeHandshake---------");
        if(request instanceof ServletServerHttpRequest){
            ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest)request;
            HttpSession session = serverHttpRequest.getServletRequest().getSession();
            if(null != session){
                logger.info("攔截請求,存入attribute,酒店id:"+session.getAttribute("hotelid"));
                if(null!=session.getAttribute("hotelid")){
                    attributes.put("hotelid", session.getAttribute("hotelid"));
                }
            }
        }
        return super.beforeHandshake(request, response, wsHandler, attributes);
    }
    
    @Override
    public void afterHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception ex) {
        // TODO Auto-generated method stub
        logger.info("-----------afterHandshake--------------");
        super.afterHandshake(request, response, wsHandler, ex);
    }
}

 

前端頁面(簡單的不能再簡單,沒有考慮瀏覽器支不支持)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
    <script language="JavaScript" src="jquery/jquery-1.11.3.min.js" charset="UTF-8"></script>
    <script type="text/javascript">
        var ws = 
        $(function(){
            $.ajaxSettings.async=false;
            $.post('<%=basePath%>/show/doSaveSession',{'hotelid':1},function(data){
                console.log("執行保存session");//模擬先登錄
            });
            $.ajaxSettings.async=true;
            ws = new WebSocket("ws://localhost:7001/show");
            
           ws.onopen = function () {
              console.log("建立鏈接");
            
           }
           ws.onclose = function () {
              console.log("onclose");
           }
     
           ws.onmessage = function (msg) {
                   console.log("----------------");
                console.log(msg.data);
           }
        });
        
    </script>

  </head>
  
  <body>
    This is my JSP page. <br>

  </body>
</html>

 

執行結果:

前台

 

后台:

 

 

ps:2018-11-19 更新,后來測試一下,不用提前登陸,直接在前端連socket的路徑上面加參數,而后在攔截器的

beforeHandshake中就可把連接的用戶存入map


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM