Spring+stomp+webSocket+SockJS簡単なブロードキャストメッセージと個人メッセージの購読を実現

34111 ワード

個人初のCSDNブログでは、自分のIT成長過程を記録しています.
WebSocketに触れるのは、プロジェクトに画像レポートクラスのモニタリングページがあるため、データはページロード後ajaxバックグラウンドで取得してページに表示され、モニタリングデータはリアルタイムで変化し、データの時効性を体現する必要があるため、webSocketを採用してクライアントとサービス側の長接続通信を実現し、クライアントがデータの取得を繰り返し要求することを避ける.実装の構想は,タイミングタスクによって定期的に最新データを取得し,webSocketを介してサービス側からブロードキャストし,クライアントがこのブロードキャストメッセージを傍受し,最新データを展示することである.余計なことを言わない.1.まずこれはssmプロジェクトです.スプリング入りのwebSocketパッケージは、4.0以上のパッケージでなければなりませんが、ここでは4.1を使いました.1: spring-messaging-4.1.1.RELEASE.jar spring-websocket-4.1.1.RELEASE.jar 2. web.xmlのfilterとservletにはtrueの構成が必要です.3.springmvcのプロファイルに導入されたwebSocketプロファイルを構成します.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:websocket="http://www.springframework.org/schema/websocket"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/websocket  
    http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
    <bean class="org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean">
        <property name="maxTextMessageBufferSize" value="8192"/>
        <property name="maxBinaryMessageBufferSize" value="8192"/>
        <property name="maxSessionIdleTimeout" value="900000"/>
        <property name="asyncSendTimeout" value="5000"/>
    bean>

    
    <bean id="webSocketMessageUtil" class="com.lancy.webSocket.common.WebSocketMessageUtil"/>
beans>
  • 注釈で定義されたwebSocketの構成クラス
  • package com.lancy.webSocket.action;
    
    import org.springframework.messaging.simp.config.MessageBrokerRegistry;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
    import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
    import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
    
    import com.lancy.webSocket.handler.StompMessageHandshakeHandler;
    import com.lancy.webSocket.handler.WebSocketHandshakeInterceptor;
    
    
    @EnableWebSocketMessageBroker
    @Controller
    public class WebSocketMessageAction extends AbstractWebSocketMessageBrokerConfigurer{
    
        /**
         *  "/webSocket"     STOMP  ,                     ,
         *       ,                 ,      , 
         *        url="/applicationName/webSocket" STOMP server    。        url;
         */
        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
            //  websocket,    ws://host:port/   /webSocket   
            registry.addEndpoint("/webSocket")
                    .setHandshakeHandler(new StompMessageHandshakeHandler())
                    .addInterceptors(new WebSocketHandshakeInterceptor())
                    .withSockJS();//     SockJS         
        }
    
        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
            registry.enableSimpleBroker("/topic","/user");//      topic user                 
            registry.setApplicationDestinationPrefixes("/ws");//                        "/ws"    
            registry.setUserDestinationPrefix("/user");//                        ,   "/user"
        }
    }

    ここで、StompMessageHandshakeHandlerクラスコードは次のとおりです.
    package com.lancy.webSocket.handler;
    
    import java.security.Principal;
    import java.util.Map;
    
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
    
    /**
     *              session、cookie         ,                   ?
     *         。         
     *
     */
    public class StompMessageHandshakeHandler extends DefaultHandshakeHandler{
    
        @Override
        protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
                Map attributes) {
            return super.determineUser(request, wsHandler, attributes);
        }
    }

    WebSocketHandshakeInterceptorクラス:
    package com.lancy.webSocket.handler;
    
    import java.util.Map;
    
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
    
    /**
     *        ,      ,  
     *
     */
    public class WebSocketHandshakeInterceptor extends HttpSessionHandshakeInterceptor{
    
        @Override
        public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                Exception ex) {
            super.afterHandshake(request, response, wsHandler, ex);
        }
    
        @Override
        public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                Map attributes) throws Exception {
            return super.beforeHandshake(request, response, wsHandler, attributes);
        }
    }

    WebSocketHandshakeHandlerクラス:
    package com.lancy.webSocket.handler;
    
    import org.springframework.web.socket.CloseStatus;
    import org.springframework.web.socket.WebSocketMessage;
    import org.springframework.web.socket.WebSocketSession;
    import org.springframework.web.socket.handler.TextWebSocketHandler;
    
    /**
     * WebSocket     
     * @ClassName: WebSocketHandshakeHandler.java
     * @Description: WebSocket     
     */
    public class WebSocketHandshakeHandler extends TextWebSocketHandler {  
    
        @Override
        public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
            super.afterConnectionClosed(session, status);
        }
    
        @Override
        public void afterConnectionEstablished(WebSocketSession session) throws Exception {
            super.afterConnectionEstablished(session);
        }
    
        @Override
        public void handleMessage(WebSocketSession session, WebSocketMessage> message) throws Exception {
            super.handleMessage(session, message);
        }
    }  

    メッセージエンティティクラスをカスタマイズし、メッセージをカプセル化します.
    package com.lancy.webSocket.common;
    
    /**
     *                
     *
     */
    public class WebSocketMessage {
    
        /**
         *       ,    :/topic/* ,*     ,   monitor,           :/topic/monitor
         *       ,    :/*,*     ,     message,         :/user/{        ID}/message
         */
        //          
        private String distination;
        private Object data;//         
        private String userId;//     ,             
    
        public String getDistination() {
            return distination;
        }
        public void setDistination(String distination) {
            this.distination = distination;
        }
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
        public String getUserId() {
            return userId;
        }
        public void setUserId(String userId) {
            this.userId = userId;
        }
    }

    WebSocketメッセージ送信のツールクラス
    package com.lancy.webSocket.common;
    
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingDeque;
    
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.messaging.simp.SimpMessagingTemplate;
    
    import com.lancy.myBatis.common.StringUtils;
    
    /**
     *                           ,        。
     *
     */
    public class WebSocketMessageUtil implements Runnable{
    
        static Logger log = Logger.getLogger(WebSocketMessageUtil.class); 
    
        private static SimpMessagingTemplate messageingTemplate;
        private static BlockingQueue wsQueue = new LinkedBlockingDeque<>();
    
        public WebSocketMessageUtil() {
            new Thread(this).start();
        }
    
        @Autowired
        public void setTemplate(SimpMessagingTemplate t){
            WebSocketMessageUtil.messageingTemplate = t;
        }
    
        public static void addMessage(WebSocketMessage msg){
            try{
                wsQueue.put(msg);
            }catch(InterruptedException e){
                log.error("        ");
            }
        }
    
        public static void sendMessage(WebSocketMessage msg){
            if(StringUtils.isBlank(msg.getUserId())){
                messageingTemplate.convertAndSend(msg.getDistination(),msg);
            }else{
                messageingTemplate.convertAndSendToUser(msg.getUserId(), msg.getDistination(), msg);
            }
        }
    
        @Override
        public void run() {
            log.info(">>>>>>>        ,      。");
            while (true) {
                try {
                    WebSocketMessage msg = wsQueue.take();
                    if(msg!=null){
                        WebSocketMessageUtil.sendMessage(msg);
                    }
                } catch (Exception ex) {}
            }
        }
    }

    それからspringタイミングタスクを構成して、タイミング実行の方法の中でメッセージの追加を行って、参照コード
    public void testWebSocket() {
            WebSocketMessage msg = new WebSocketMessage();
            msg.setDistination("/topic/lancy/testWebSocket/new");
            msg.setData("test....");
            WebSocketMessageUtil.addMessage(msg);
    }

    フロントインタフェースは、まず2つのjsファイルsockjsを導入する.min.jsとstomp.min.js
    <script type="text/javascript" src="${ctx}/js/socket/sockjs.min.js">script>
    <script type="text/javascript" src="${ctx}/js/socket/stomp.min.js">script>

    具体的なページは以下の通りです.
    "java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    "c" uri="http://java.sun.com/jsp/jstl/core" %>
    <c:set var="ctx" value="${pageContext.request.contextPath}" />
    
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title heretitle>
    
    <link rel="stylesheet" type="text/css" href="${ctx}/css/default.css" />
    <link rel="stylesheet" type="text/css" href="${ctx}/js/easyui/themes/default/easyui.css">
    <link rel="stylesheet" type="text/css" href="${ctx}/js/easyui/themes/icon.css">
    <link rel="stylesheet" type="text/css" href="${ctx}/js/easyui/demo/demo.css">
    <script type="text/javascript" src="${ctx}/js/jquery.min.js">script>
    <script type="text/javascript" src="${ctx}/js/socket/sockjs.min.js">script>
    <script type="text/javascript" src="${ctx}/js/socket/stomp.min.js">script>
    <script type="text/javascript" src="${ctx}/js/app_common.js">script>
    <script type="text/javascript" src="${ctx}/js/easyui/jquery.easyui.min.js">script>
    <script type="text/javascript"> 
    
        var stompClient = null;  
    
        function setConnected(connected) {  
            document.getElementById('connect').disabled = connected;  
            document.getElementById('disconnect').disabled = !connected;  
            document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';  
            document.getElementById('response').innerHTML = '';  
        }  
    
        function connect() {  
            var socket = new SockJS('/myBookstore/webSocket');//        ,                   
            stompClient = Stomp.over(socket);              
            stompClient.connect({}, function(frame) {  
                setConnected(true);  
                console.log('Connected: ' + frame); 
                //      
                stompClient.subscribe('/topic/lancy/testWebSocket/new', function(greeting){  
                    showGreeting(greeting.body);  
                });
    
                //      
                stompClient.subscribe('/user/1/testUser', function(greeting){  
                    showGreeting(greeting.body);  
                }); 
            });  
        }  
    
        function disconnect() {  
            if (stompClient != null) {  
                stompClient.disconnect();  
                setConnected(false);  
                console.log("Disconnected");  
            }  
        }  
    
        //        
        function sendName() {  
            var name = document.getElementById('name').value;
            stompClient.send("/ws/webSocket/testWithServer", {'name': 'xiao','syn':'wang'}, JSON.stringify({'message': name }));  
        }  
    
        function showGreeting(message) {  
            var response = document.getElementById('response');  
            var p = document.createElement('p');  
            p.style.wordWrap = 'break-word';  
            p.appendChild(document.createTextNode(message));  
            response.appendChild(p);  
        }
    
    script>
    head>
    <body class="easyui-layout">
        <div>  
            <div>  
                <button id="connect" onclick="connect();">Connectbutton>  
                <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnectbutton>  
            div>  
            <div id="conversationDiv">  
                <label>What is your name?label><input type="text" id="name" />  
                <button id="sendName" onclick="sendName();">Send allbutton>  
                <p id="response">p>  
            div>  
        div> 
    
    
    body>
    html>

    jsメソッドのsendNameは、サービス側のメッセージに対応するクラスに送信されます.
    package com.lancy.webSocket.action;
    
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.messaging.handler.annotation.Header;
    import org.springframework.messaging.handler.annotation.Headers;
    import org.springframework.messaging.handler.annotation.MessageMapping;
    import org.springframework.messaging.simp.SimpMessagingTemplate;
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class WebSocketTestAction {
    
        @Autowired
        private SimpMessagingTemplate simpMessagingTemplate;
    
        @MessageMapping("/webSocket/testWithServer")
        //    stompClient.send("/ws/webSocket/testWithServer", 
        //{'name': 'xiao','syn':'wang'}, JSON.stringify({'message': name }));    
        public String send(String message,@Header("name")String name,
                @Headers Map headers){
            System.out.println(message);
            System.out.println(name);
            System.out.println(headers);
            simpMessagingTemplate.convertAndSend("/user/1/testUser","       ");
            return "";
        }
    }
    

    これで終わりです.