1. 程式人生 > 實用技巧 >【轉】 springboot+websocket示例

【轉】 springboot+websocket示例

【轉】 springboot+websocket示例

1、新建maven工程

工程結構如下:

完整的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>com.websocket.demo</groupId> <artifactId>websocket-demo</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <
artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.RELEASE</version> </parent> <dependencies> <!-- thymeleaf 模板的配置 --> <dependency> <groupId>org.springframework.boot</groupId> <
artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- spring websocket的配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>1.4.5.RELEASE</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

2、application.properties 的配置如下

#thymeleaf start
#spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
#開發時關閉快取,不然沒法看到實時頁面
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
#thymeleaf end


server.port=8082

3、啟動類

package com.websocket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author Administrator
 * @date 2018/08/18
 */
@SpringBootApplication
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

4、WebsocketConfig 類進行了websocket的配置

package com.websocket.config;

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;

/**
 * @author hzb
 * @date 2018/09/30
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        //啟用/userTest,/topicTest,兩個訊息字首
        config.enableSimpleBroker("/userTest","/topicTest");
        //如果不設定下面這一句,用convertAndSendToUser來發送訊息,前端訂閱只能用/user開頭。
        config.setUserDestinationPrefix("/userTest");
        //客戶端(html等)向服務端傳送訊息的字首
        config.setApplicationDestinationPrefixes("/app");
    }
    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        //客戶端和服務端進行連線的endpoint
        stompEndpointRegistry.addEndpoint("/websocket-endpoint").setAllowedOrigins("*").withSockJS();
    }
}

5、訊息管理實現類

package com.websocket.controller;

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.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author hzb
 * @date 2018/09/30
 */
@Controller
@EnableScheduling
public class WebsocketMsgController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @GetMapping("/")
    public String index() {
        return "index";
    }

    /**
     * index.html將message傳送給後端,後端再將訊息重組後傳送到/topicTest/web-to-server-to-web
     * @param message
     * @return
     * @throws Exception
     */
    @MessageMapping("/send")
    @SendTo("/topicTest/web-to-server-to-web")
    public String send(String message) throws Exception {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return "伺服器將原訊息返回: "+df.format(new Date())+" :" + message;
    }

    /**
     * 最基本的伺服器端主動推送訊息給前端
     * @return
     * @throws Exception
     */
    @Scheduled(fixedRate = 1000)
    public String serverTime() throws Exception {
        // 發現訊息
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        messagingTemplate.convertAndSend("/topicTest/servertime", df.format(new Date()));
        return "servertime";
    }

    /**
     * 以下面這種方式傳送訊息,前端訂閱訊息的方式為: stompClient.subscribe('/userTest/hzb/info' 
     * @return
     * @throws Exception
     */
    @Scheduled(fixedRate = 1000)
    public String serverTimeToUser() throws Exception {
        // 發現訊息
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //這裡雖然沒有指定傳送字首為/userTest,但是在WebsocketConfig.java中設定了config.setUserDestinationPrefix("/userTest"),
        //否則預設為/user
        messagingTemplate.convertAndSendToUser("hzb","/info", df.format(new Date()));
        return "serverTimeToUser";
    }
}

前端程式碼:index.html

<!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,
                sendMessage : '',
                receivMessages : []
            };

            //連線
            $scope.connect = function() {
                var socket = new SockJS('/websocket-endpoint');
                stompClient = Stomp.over(socket);
                stompClient.connect({}, function(frame) {
                    // 訂閱後端主動推訊息到前端的topic
                    stompClient.subscribe('/topicTest/servertime', function(r) {
                        $scope.data.time = '當前伺服器時間:' + r.body;
                        $scope.data.connected = true;
                        $scope.$apply();
                    });
                    // 閱後端主動推訊息到前端的topic,只有指定的使用者(hzb)收到的的訊息
                    stompClient.subscribe('/userTest/hzb/info', function(r) {
                        $scope.data.hzbtime = '當前伺服器時間:' + r.body;
                        $scope.data.connected = true;
                        $scope.$apply();
                    });
                    // 訂閱前端發到後臺,後臺又將訊息返回前臺的topic
                    stompClient.subscribe('/topicTest/web-to-server-to-web', function(msg) {
                        $scope.data.receivMessages.push(msg.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.sendMessage
                }));
            }
        });
    </script>
</head>
<body ng-app="app" ng-controller="MainController">

<h2>websocket示例</h2>
<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">
    <h4>以下是websocket的服務端主動推送訊息到頁面的例子</h4>
    <label>{{data.time}}</label> <br/> <br/>
    </div>
<div ng-show="data.connected">
    <h4>以下是websocket的服務端主動推送訊息到頁面的例子,只有hzb這個使用者收到</h4>
    <label>{{data.hzbtime}}</label> <br/> <br/>
    </div>
<div ng-show="data.connected">
    <h4>以下是websocket的客戶端發訊息到服務端,服務端再將該訊息返回到客戶端(頁面)的例子</h4>
            <input type="text" ng-model="data.sendMessage" placeholder="請輸入內容..." />
    <button ng-click="send()" type="button">傳送</button>
    <br/>
    <table>
    <thead>
<tr>
    <th>訊息內容:</th>
    </tr>
    </thead>
    <tbody>
<tr ng-repeat="messageContent in data.receivMessages">
    <td>{{messageContent}}</td>
    </tr>
    </tbody>
    </table>
    </div>
</body>
</html>

執行效果

沒有點“連線”之前

點了“連線”之後

輸入內容:點擊發送