WebSocket 不做过多得介绍,这里有篇比较全面得文章      Spring Boot系列十六 WebSocket简介和spring boot集成简单消息代理

我这里是精简版,只挑出核心代码记录。免得浪费大家时间

⒈项目导入依赖

         <!-- 引入 websocket 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

⒉编写websocket配置

 package cn.coreqi.consumer.config;

 import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; /**
* 配置消息代理,默认情况下使用内置的消息代理。
* @EnableWebSocketMessageBroker 此注解表示使用STOMP协议来传输基于消息代理的消息,此时可以在@Controller类中使用@MessageMapping
*/
@Configuration
@EnableWebSocketMessageBroker
//SpringBoot2.x将extends AbstractWebSocketMessageBrokerConfigurer改为 implements WebSocketMessageBrokerConfigurer
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 注册 Stomp的端点 配置对外暴露访问的端点
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket-simple") //添加STOMP协议的端点。
// 这个URL是供WebSocket客户端或SockJS客户端连接服务端访问的地址。
.setAllowedOrigins("*") //添加允许跨域访问
.withSockJS(); //指定端点使用SockJS协议
} /**
* 配置消息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//启动简单Broker,客户端请求地址符合配置的前缀,消息才会发送到这个broker
//客户端订阅当前服务端时需要添加以下请求前缀,topic一般用于广播推送,queue用于点对点推送
registry.enableSimpleBroker("/userTest","/topicTest");
//如果不设置下面这一句,使用SimpMessagingTemplate.convertAndSendToUser向指定用户推送消息时
//订阅前缀只能为/user,例如前端订阅为/user/fanqi/info
registry.setUserDestinationPrefix("/userTest");
//客户端(html客户端、java客户端等)向服务端发送消息的请求前缀
registry.setApplicationDestinationPrefixes("/app");
} }

⒊编写控制器

 package cn.coreqi.consumer.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.RequestMapping; import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date; @Controller
@EnableScheduling //定时任务支持
public class WebSocketController { @Autowired
private SimpMessagingTemplate messagingTemplate; @RequestMapping("/")
public String index() {
return "index";
} /**
* 这里用于客户端推送消息到服务端,推送地址为:setApplicationDestinationPrefixes("/app")设置得前缀加上@MessageMapping注解得地址
* 此处为/app/send
* 当前方法处理后将结果转发给@SendTo注解得地址,如果没有指定,则采用默认
* @MessageMapping 指定要接收消息的地址,类似@RequestMapping。除了注解到方法上,也可以注解到类上
* @SendTo 默认消息将被发送到与传入消息相同的目的地,但是目的地前面附加前缀(默认情况下为"/topic")
* @param message 客户端推送过来得消息,一般生产环境会封装
* @return
* @throws Exception
*/
@MessageMapping("/send")
@SendTo("/topicTest/web-to-server-to-web")
public String greeting(String message) throws Exception {
// 模拟延时,以便测试客户端是否在异步工作
Thread.sleep(1000);
return "Hello, " + message + "!";
} /**
* 最基本的服务器端主动推送消息给客户端
* @return
* @throws Exception
*/
@Scheduled(initialDelay = 7000,fixedRate = 2000)
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";
} /**
* 服务端推送消息到指定用户得客户端
* 例如以下将会推送到
* 因为设置了setUserDestinationPrefix("/userTest"),因此推送到/userTest/fanqi/info
* 如果没有设置setUserDestinationPrefix(),则默认前端为user,将会推送到/user/fanqi/info
* 客户端订阅/userTest/fanqi/info将会收到服务端推送得消息
* @return
* @throws Exception
*/
@Scheduled(initialDelay = 7000,fixedRate = 2000)
public String serverTimeToUser() throws Exception {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
messagingTemplate.convertAndSendToUser("fanqi","/info", df.format(new Date()));
return "serverTimeToUser";
}
}

⒋前端websocket客户端代码

 <!DOCTYPE html>
<html>
<head>
<title>玩转spring boot——websocket</title>
<script src="https://cdn.bootcss.com/angular.js/1.5.6/angular.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="https://cdn.bootcss.com/sockjs-client/1.3.0/sockjs.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.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-simple');
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/fanqi/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>
05-28 05:31