springboot+websocket實現頁面後臺長連線
阿新 • • 發佈:2018-11-04
在自己整合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"這樣也是連結不通的,總之,瀏覽器訪問地址和頁面連結後臺地址保持一致就可以了!