1. 程式人生 > >springboot+websocket實現頁面後臺長連線

springboot+websocket實現頁面後臺長連線

    在自己整合websocket時踩了一些坑,給大家分享出來希望可以幫到有需要的小夥伴,我的測試案例中有什麼問題請指出,大家共同學習,現在開始上程式碼;

第一步,新增pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
> <modelVersion>4.0.0</modelVersion> <groupId>zenithink-demo</groupId> <artifactId>zenithink-demo</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId
>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version> <com.alibaba.dubbo.version>2.5.3</com.alibaba.dubbo.version> <dubbo-spring-boot>1.0.0</dubbo-spring-boot> <org.apache.zookeeper.version>3.4.6</org.apache.zookeeper.version> <com.github.sgroschupf.zkclient.version>0.1</com.github.sgroschupf.zkclient.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--檢視解析器依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> </dependency> <!--Http client元件--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.5</version> </dependency> <!--json物件依賴--> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> <!--字串工具依賴--> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!--日誌依賴--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.6</version> </dependency> <!--spring data mongodb--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <!--引入websocket依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>lombok</groupId> <artifactId>lombok</artifactId> <version>1.0</version> </dependency> </dependencies> </project>

第二步,新增所需封裝實體類

public class SocketMessage {

    public String message;

    public String date;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }
}

第三步,websochet配置物件

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

/**
 * websocket設定
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        //設定瀏覽器接收的服務字首,同時也是後臺服務推送的字首
        config.enableSimpleBroker("/topic");
        //設定瀏覽器傳送訊息的服務字首,也就是後臺服務接收前臺資訊的字首
        config.setApplicationDestinationPrefixes("/app");
    }

    //新增服務端點 瀏覽器連結這個地址
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/my-websocket").withSockJS();
    }

}

第四步,新增前端控制器

import com.demo.entity.SocketMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * websocket測試前端控制器
 */
@Controller
public class App {

    /**
     * websochet訊息傳送物件
     */
    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    /**
     * 跳轉到測試頁面
     * @return
     */
    @GetMapping("/")
    public String index() {
        return "test01";
    }

    //測試頁面顯示後臺訊息推送次數
    private int count=0;

    //接收瀏覽器訊息路徑設定
    @MessageMapping("/send")
    //服務端向瀏覽器推送地址設定
    @SendTo("/topic/send")
    public SocketMessage send(SocketMessage message) throws Exception {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        message.date = "瀏覽器訊息";
        return message;
    }

    //由後臺傳送到瀏覽器服務
    @SendTo("/topic/callback")
    //定時5秒給頁面推一次資料
    @Scheduled(cron="0/5 * * * * ?")
    public Object callback() throws Exception {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("推送訊息了"+df.format(new Date()));
        //向頁面這個地址推送訊息
            messagingTemplate.convertAndSend("/topic/callback","客戶端訊息"+count );
            count++;
        return null;
    }
}

第五步,新增測試頁面

<!DOCTYPE html>
<html>
<head>
    <title>spring boot——websocket測試頁面</title>
    <script src="//cdn.bootcss.com/angular.js/1.5.6/angular.min.js"></script>
    <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
    <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
    <script type="text/javascript">


        var stompClient = null;

        var app = angular.module('app', []);
        app.controller('MainController', function($rootScope, $scope, $http) {

            $scope.data = {
                //連線狀態
                connected : false,
                //訊息
                message : '',
                rows : []
            };

            //連線
            $scope.connect = function() {
                //特別注意連結的IP和瀏覽器訪問地址必須保持一致,不然就會出現連結不上的問題
               var socket = new SockJS('http://10.0.0.253:1214/my-websocket');
                stompClient = Stomp.over(socket);
                stompClient.connect({}, function(frame) {
                    // 接收後臺服務推送訊息
                    stompClient.subscribe('/topic/send', function(msg) {
                        $scope.data.rows.push(JSON.parse(msg.body));
                        $scope.data.connected = true;
                        $scope.$apply();
                    });
                    // 接收後臺服務推送訊息
                    stompClient.subscribe('/topic/callback', function(r) {
                        $scope.data.time = '當前伺服器推送內容:' + r.body;
                        $scope.data.connected = true;
                        $scope.$apply();
                    });

                    $scope.data.connected = true;
                    $scope.$apply();
                });
            };

            $scope.disconnect = function() {
                if (stompClient != null) {
                    stompClient.disconnect();
                }
                $scope.data.connected = false;
            }
            //瀏覽器向後臺推送訊息
            $scope.send = function() {
                stompClient.send("/app/send", {}, JSON.stringify({
                    'message' : $scope.data.message
                }));
            }
        });
        /*]]>*/
    </script>
</head>
<body ng-app="app" ng-controller="MainController">



<label>WebSocket連線狀態:</label>
<button type="button" ng-disabled="data.connected" ng-click="connect()">連線</button>
<button type="button" ng-click="disconnect()"
        ng-disabled="!data.connected">斷開</button>
<br />
<br />
<div ng-show="data.connected">
    <label>{{data.time}}</label> <br /> <br /> <input type="text"
                                                      ng-model="data.message" placeholder="請輸入內容..." />
    <button ng-click="send()" type="button">傳送</button>
    <br /> <br /> 訊息列表: <br />
    <table>
        <thead>
        <tr>
            <th>接收瀏覽器內容</th>
            <th>後臺推送內容</th>
        </tr>
        </thead>
        <tbody>
        <tr ng-repeat="row in data.rows">
            <td>{{row.message}}</td>
            <td>{{row.date}}</td>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

第六步,頁面效果展示

總結:

    到這就算大功告成,不過連結後臺服務的時候折騰了很久,最終發現,通過sockjs連結的時候不加IP埠"/my-websocket"連結是可以的,如果改成"127.0.0.1:1214/my-websocket"這樣就連結不成功,後來改成"http://127.0.0.1:1214/my-websocket"又可以,通過"ws://127.0.0.1:1214/my-websocket"這樣也是連結不通的,總之,瀏覽器訪問地址和頁面連結後臺地址保持一致就可以了!