Spring整合WebSocket實現服務端推送消息給客戶端


1、pom.xml額外增加依賴

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>${spring.version}</version>
</dependency>

2、自定義JoyinMessageHandler繼承WebSocketHandler,處理消息

/*
 * 文件名:JoyinMessageHandler.java
 * 版權:Copyright 2016-2017 JoyinTech. Co. Ltd. All Rights Reserved.
 * 描述:中信銀行資管系統
 * 修改人:Administrator
 * 修改時間:2020年1月16日
 * 修改內容:新建
 * 系統名稱:中信銀行資管系統
 */

package com.joyintech.tams.framework;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

/**
 * 〈一句話功能簡述〉 〈功能詳細描述〉
 * 
 * @author Administrator
 * @version 1.0 2020年1月16日
 * @see JoyinMessageHandler
 * @since 1.0
 */
@Component
public class JoyinMessageHandler implements WebSocketHandler {

    /**
     * 用戶
     */
    public static final String USER_KEY = "socket_user";

    /**
     * 用戶數量
     */
    private final static int size = 300;

    /**
     * userMap:存儲用戶連接webscoket信息
     * 
     * @since JDK 1.7
     */
    private final static Map<String, WebSocketSession> userMap;
    static {
        userMap = new ConcurrentHashMap<String, WebSocketSession>(size);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status)
        throws Exception {
        String userId = this.getUserId(session);
        if (!StringUtils.isEmpty(userId)) {
            userMap.remove(userId);
            System.err.println(userId + "用戶已成功關閉會話");
        }
        else {
            System.err.println("關閉時,獲取用戶id為空");
        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session)
        throws Exception {
        String userId = this.getUserId(session);
        if (!StringUtils.isEmpty(userId)) {
            userMap.put(userId, session);
        }
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message)
        throws Exception {
        String msg = message.toString();
        String userId = this.getUserId(session);
        System.err.println("該" + userId + "用戶發送的消息是:" + msg);
        message = new TextMessage("服務端已經接收到消息,msg=" + msg);
        session.sendMessage(message);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable e)
        throws Exception {
        WebSocketMessage<String> message = new TextMessage("異常信息:" + e.getMessage());
        session.sendMessage(message);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    private String getUserId(WebSocketSession session) {
        try {
            String userId = (String)session.getAttributes().get(USER_KEY);
            return userId;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 給某個用戶發送消息
     *
     * @param userId
     * @param message
     */
    public void sendMessageToUser(String userId, TextMessage message) {
        WebSocketSession webSocketSession = userMap.get(userId);
        if (webSocketSession != null && webSocketSession.isOpen()) {
            try {
                webSocketSession.sendMessage(message);
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3、編寫攔截器WebSocketInterceptor繼承HttpSessionHandshakeInterceptor實現用戶的綁定

/*
 * 文件名:WebSocketInterceptor.java
 * 版權:Copyright 2016-2017 JoyinTech. Co. Ltd. All Rights Reserved.
 * 描述:中信銀行資管系統
 * 修改人:Administrator
 * 修改時間:2020年1月16日
 * 修改內容:新建
 * 系統名稱:中信銀行資管系統
 */

package com.joyintech.tams.framework.interceptor;

import java.util.Map;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import com.joyintech.tams.framework.JoyinMessageHandler;

/**
 * 〈一句話功能簡述〉 〈功能詳細描述〉
 * 
 * @author Administrator
 * @version 1.0 2020年1月16日
 * @see WebSocketInterceptor
 * @since 1.0
 */
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {

    /**
     * TODO 描述該方法的實現功能.
     * 
     * @see org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor#beforeHandshake(org.springframework.http.server.ServerHttpRequest,
     *      org.springframework.http.server.ServerHttpResponse,
     *      org.springframework.web.socket.WebSocketHandler, java.util.Map)
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
                                   WebSocketHandler wsHandler, Map<String, Object> attributes)
        throws Exception {
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest)request;
            // 獲取參數
            String userId = serverHttpRequest.getServletRequest().getParameter("userId");
            attributes.put(JoyinMessageHandler.USER_KEY, userId);
        }

        return true;
    }
}

4、修改spring配置文件,增加以下配置

<!-- 配置webSockte -->
    <websocket:handlers allowed-origins="*">
    <!-- 前端握手請求地址 -->
        <websocket:mapping path="/socketServer" handler="joyinMessageHandler"/>
        <websocket:handshake-interceptors>
            <bean class="com.joyintech.tams.framework.interceptor.WebSocketInterceptor"/>
        </websocket:handshake-interceptors>
    </websocket:handlers>

5、修改js增加以下方法

var homepage = function() {
    return {
        /**
         * 綁定用戶信息
         */
        bindUserInfo : function() {
            if('WebSocket' in window) {
                var websocket = new WebSocket("ws://"+baseFullPath+"socketServer?userId="+loginUserId);
                // 打開連接時
                websocket.onopen = function(evnt) {
                    console.log("websocket已啟用");
                };
                
                // 收到消息時
                websocket.onmessage = function(message) {
                    console.log("收到websocket消息:" + message.data);
                };
                
                //出錯時
                websocket.onerror = function(evnt) {
                    console.log("與后台握手出現問題!");
                };
                
                //關閉時
                websocket.onclose = function(evnt) {
                    console.log("正在關閉 webSocket ");
                };
            }
        },
    }
}();

jQuery(document).ready(function() {
    // 綁定用戶信息
    homepage.bindUserInfo();
})

6、修改jsp獲得baseFullPath

<%
    String path = request.getContextPath();
    String baseFullPath = request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<script type="text/javascript">
var baseFullPath = '<%=baseFullPath%>';
var loginUserId = '${user.userId}';
</script>

7、在任意地方調用com.joyintech.tams.framework.JoyinMessageHandler.sendMessageToUser(String, TextMessage)方法即可

messageHandler.sendMessageToUser("00000000000000000002", new TextMessage("發送消息給用戶00000000000000000002"));


免責聲明!

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



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