WebSocket 不做過多得介紹,這里有篇比較全面得文章 Spring Boot系列十六 WebSocket簡介和spring boot集成簡單消息代理
我這里是精簡版,只挑出核心代碼記錄。免得浪費大家時間
⒈項目導入依賴
1 <!-- 引入 websocket 依賴--> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-websocket</artifactId> 5 </dependency>
⒉編寫websocket配置
1 package cn.coreqi.consumer.config; 2 3 import org.springframework.context.annotation.Configuration; 4 import org.springframework.messaging.simp.config.MessageBrokerRegistry; 5 import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; 6 import org.springframework.web.socket.config.annotation.StompEndpointRegistry; 7 import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; 8 9 /** 10 * 配置消息代理,默認情況下使用內置的消息代理。 11 * @EnableWebSocketMessageBroker 此注解表示使用STOMP協議來傳輸基於消息代理的消息,此時可以在@Controller類中使用@MessageMapping 12 */ 13 @Configuration 14 @EnableWebSocketMessageBroker 15 //SpringBoot2.x將extends AbstractWebSocketMessageBrokerConfigurer改為 implements WebSocketMessageBrokerConfigurer 16 public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { 17 /** 18 * 注冊 Stomp的端點 配置對外暴露訪問的端點 19 * @param registry 20 */ 21 @Override 22 public void registerStompEndpoints(StompEndpointRegistry registry) { 23 registry.addEndpoint("/websocket-simple") //添加STOMP協議的端點。 24 // 這個URL是供WebSocket客戶端或SockJS客戶端連接服務端訪問的地址。 25 .setAllowedOrigins("*") //添加允許跨域訪問 26 .withSockJS(); //指定端點使用SockJS協議 27 } 28 29 /** 30 * 配置消息代理 31 * @param registry 32 */ 33 @Override 34 public void configureMessageBroker(MessageBrokerRegistry registry) { 35 //啟動簡單Broker,客戶端請求地址符合配置的前綴,消息才會發送到這個broker 36 //客戶端訂閱當前服務端時需要添加以下請求前綴,topic一般用於廣播推送,queue用於點對點推送 37 registry.enableSimpleBroker("/userTest","/topicTest"); 38 //如果不設置下面這一句,使用SimpMessagingTemplate.convertAndSendToUser向指定用戶推送消息時 39 //訂閱前綴只能為/user,例如前端訂閱為/user/fanqi/info 40 registry.setUserDestinationPrefix("/userTest"); 41 //客戶端(html客戶端、java客戶端等)向服務端發送消息的請求前綴 42 registry.setApplicationDestinationPrefixes("/app"); 43 } 44 45 }
⒊編寫控制器
1 package cn.coreqi.consumer.controller; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.messaging.handler.annotation.MessageMapping; 5 import org.springframework.messaging.handler.annotation.SendTo; 6 import org.springframework.messaging.simp.SimpMessagingTemplate; 7 import org.springframework.scheduling.annotation.EnableScheduling; 8 import org.springframework.scheduling.annotation.Scheduled; 9 import org.springframework.stereotype.Controller; 10 import org.springframework.web.bind.annotation.RequestMapping; 11 12 import java.text.DateFormat; 13 import java.text.SimpleDateFormat; 14 import java.util.Date; 15 16 @Controller 17 @EnableScheduling //定時任務支持 18 public class WebSocketController { 19 20 @Autowired 21 private SimpMessagingTemplate messagingTemplate; 22 23 24 @RequestMapping("/") 25 public String index() { 26 return "index"; 27 } 28 29 /** 30 * 這里用於客戶端推送消息到服務端,推送地址為:setApplicationDestinationPrefixes("/app")設置得前綴加上@MessageMapping注解得地址 31 * 此處為/app/send 32 * 當前方法處理后將結果轉發給@SendTo注解得地址,如果沒有指定,則采用默認 33 * @MessageMapping 指定要接收消息的地址,類似@RequestMapping。除了注解到方法上,也可以注解到類上 34 * @SendTo 默認消息將被發送到與傳入消息相同的目的地,但是目的地前面附加前綴(默認情況下為"/topic") 35 * @param message 客戶端推送過來得消息,一般生產環境會封裝 36 * @return 37 * @throws Exception 38 */ 39 @MessageMapping("/send") 40 @SendTo("/topicTest/web-to-server-to-web") 41 public String greeting(String message) throws Exception { 42 // 模擬延時,以便測試客戶端是否在異步工作 43 Thread.sleep(1000); 44 return "Hello, " + message + "!"; 45 } 46 47 /** 48 * 最基本的服務器端主動推送消息給客戶端 49 * @return 50 * @throws Exception 51 */ 52 @Scheduled(initialDelay = 7000,fixedRate = 2000) 53 public String serverTime() throws Exception { 54 // 發現消息 55 DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 56 messagingTemplate.convertAndSend("/topicTest/servertime", df.format(new Date())); 57 return "servertime"; 58 } 59 60 /** 61 * 服務端推送消息到指定用戶得客戶端 62 * 例如以下將會推送到 63 * 因為設置了setUserDestinationPrefix("/userTest"),因此推送到/userTest/fanqi/info 64 * 如果沒有設置setUserDestinationPrefix(),則默認前端為user,將會推送到/user/fanqi/info 65 * 客戶端訂閱/userTest/fanqi/info將會收到服務端推送得消息 66 * @return 67 * @throws Exception 68 */ 69 @Scheduled(initialDelay = 7000,fixedRate = 2000) 70 public String serverTimeToUser() throws Exception { 71 DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 72 messagingTemplate.convertAndSendToUser("fanqi","/info", df.format(new Date())); 73 return "serverTimeToUser"; 74 } 75 }
⒋前端websocket客戶端代碼
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>玩轉spring boot——websocket</title> 5 <script src="https://cdn.bootcss.com/angular.js/1.5.6/angular.min.js"></script> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> 7 <script src="https://cdn.bootcss.com/sockjs-client/1.3.0/sockjs.js"></script> 8 <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script> 9 <script type="text/javascript"> 10 var stompClient = null; 11 12 var app = angular.module('app', []); 13 app.controller('MainController', function($rootScope, $scope, $http) { 14 15 $scope.data = { 16 connected : false, 17 sendMessage : '', 18 receivMessages : [] 19 }; 20 21 //連接 22 $scope.connect = function() { 23 var socket = new SockJS('/websocket-simple'); 24 stompClient = Stomp.over(socket); 25 stompClient.connect({}, function(frame) { 26 // 訂閱后端主動推消息到前端的topic 27 stompClient.subscribe('/topicTest/servertime', function(r) { 28 $scope.data.time = '當前服務器時間:' + r.body; 29 $scope.data.connected = true; 30 $scope.$apply(); 31 }); 32 // 閱后端主動推消息到前端的topic,只有指定的用戶(hzb)收到的的消息 33 stompClient.subscribe('/userTest/fanqi/info', function(r) { 34 $scope.data.hzbtime = '當前服務器時間:' + r.body; 35 $scope.data.connected = true; 36 $scope.$apply(); 37 }); 38 // 訂閱前端發到后台,后台又將消息返回前台的topic 39 stompClient.subscribe('/topicTest/web-to-server-to-web', function(msg) { 40 $scope.data.receivMessages.push(msg.body); 41 $scope.data.connected = true; 42 $scope.$apply(); 43 }); 44 45 46 $scope.data.connected = true; 47 $scope.$apply(); 48 }); 49 }; 50 51 $scope.disconnect = function() { 52 if (stompClient != null) { 53 stompClient.disconnect(); 54 } 55 $scope.data.connected = false; 56 } 57 58 $scope.send = function() { 59 stompClient.send("/app/send", {}, JSON.stringify({ 60 'message' : $scope.data.sendMessage 61 })); 62 } 63 }); 64 </script> 65 </head> 66 <body ng-app="app" ng-controller="MainController"> 67 68 <h2>websocket示例</h2> 69 <label>WebSocket連接狀態:</label> 70 <button type="button" ng-disabled="data.connected" ng-click="connect()">連接</button> 71 <button type="button" ng-click="disconnect()" ng-disabled="!data.connected">斷開</button> 72 <br/> 73 <br/> 74 <div ng-show="data.connected"> 75 <h4>以下是websocket的服務端主動推送消息到頁面的例子</h4> 76 <label>{{data.time}}</label> <br/> <br/> 77 </div> 78 <div ng-show="data.connected"> 79 <h4>以下是websocket的服務端主動推送消息到頁面的例子,只有hzb這個用戶收到</h4> 80 <label>{{data.hzbtime}}</label> <br/> <br/> 81 </div> 82 <div ng-show="data.connected"> 83 <h4>以下是websocket的客戶端發消息到服務端,服務端再將該消息返回到客戶端(頁面)的例子</h4> 84 <input type="text" ng-model="data.sendMessage" placeholder="請輸入內容..." /> 85 <button ng-click="send()" type="button">發送</button> 86 <br/> 87 <table> 88 <thead> 89 <tr> 90 <th>消息內容:</th> 91 </tr> 92 </thead> 93 <tbody> 94 <tr ng-repeat="messageContent in data.receivMessages"> 95 <td>{{messageContent}}</td> 96 </tr> 97 </tbody> 98 </table> 99 </div> 100 </body> 101 </html>