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>