版权声明:转载请取得博主同意 https://blog.csdn.net/weixin_43050247/article/details/89682675
WebScoket (订阅与广播模式)
1.maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.configure配置
package com.myself.computerThinking.Subscription;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Component
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
/**
* 用户可以订阅来自“/topic,/user”为前缀的消息
* 客户端只可以订阅这个前缀的主题
*/
registry.enableSimpleBroker("/topic","/user");
/**
* 客户端发送过来的消息,需要以“/app”为前缀,再通过Broker转发给响应的Controller
*/
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
/**
* 路径:"websocket/socketServer.action"被注册为STOMP端点,对外暴露,客户端通过该路径接入webScoket服务
*/
registry.addEndpoint("websocket/socketServer.action")
.setAllowedOrigins("*") //设置可以跨域请求
.withSockJS(); // 添加SockJS支持
}
}
withSockJS()
:添加SockJS的支持。(SockJS有关信息:https://blog.csdn.net/john_62/article/details/78208177)
SockJS是一个浏览器JavaScript库,它提供了一个类似于网络的对象。SockJS提供了一个连贯的、跨浏览器的Javascript API,它在浏览器和web服务器之间创建了一个低延迟、全双工、跨域通信通道。按浏览器是否支持WebSocket,以此使用三类传输对象:WebSocket
> HTTP流
> HTTP长轮询
- 如果添加了SockJS()支持,前段页面代码:
var socket = new SockJS(url);
url为http、https开头 - 没有添加支持,
var socket = new WebSocket(url);
url为ws、wss开头
添加路径拦截器
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler").withSockJS();
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
3.spring boot静态资源
package com.myself.computerThinking.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
super.addResourceHandlers(registry);
}
}
4.Controller&Server
@Controller
public class subController {
@RequestMapping(value = "/stomp")
public String getStopm(){
return "stomp";
}
/**
* 接收前端发送消息: stompClient.send("/app/welcome", {atytopic:"greetings"}, "123");
* 并广播出去,广播地址为:/topic/CCC
* @param message
* @param topic
* @param headers
* @return
*/
@MessageMapping("/welcome")
@SendTo("/topic/CCC")
public String sendMessage(String message, @Header("atytopic")String topic, @Headers Map<String,Object> headers) {
System.out.println(topic);
System.out.println(headers);
System.out.println(message);
return message;
}
}
package com.myself.computerThinking.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Component;
@Component
public class TaskServiceImpl implements TaskService {
private final static Logger logger= LoggerFactory.getLogger(TaskServiceImpl.class);
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@Scheduled(cron="0/10 * * * * ? ") //CRON表达式每10秒执行一次
@Override
public void selectCurDayDepotOrderInfo() {
logger.info("=====================AAA频道每10秒执行一次刷新=====================");
simpMessagingTemplate.convertAndSend("/topic/AAA","123");
}
@Scheduled(cron="0/13 * * * * ? ")
@Override
public void selectCustomerOrderInfo() {
logger.info("=====================BBB频道每13秒执行一次刷新=====================");
simpMessagingTemplate.convertAndSend("/topic/AAA", "456");
}
}
- 使用
@Scheduled
,需要开启计时注解@enablescheduling
@MessageMapping("/welcome")
接受前端传递 send的值,该页面要有@controller
注释@SendTo("/topic/CCC")
发送消息给订阅了CCC主题的前端- @SendTo 与 @SendToUser 是Spring的STOMP协议中注解的标签。
@SendTo会将接收到的消息发送到指定的路由目的地,所有订阅该消息的用户都能收到,属于广播。
@SendToUser消息目的地有UserDestinationMessageHandler来处理,会将消息路由到发送者对应的目的地。默认该注解前缀为/user。如:用户订阅/user/hi ,在@SendToUser(’/hi’)查找目的地时,会将目的地的转化为/user/{name}/hi, 这个name就是principal的name值,该操作是认为用户登录并且授权认证,使用principal的name作为目的地标识。发给消息来源的那个用户。(就是谁请求给谁,不会发给所有用户,区分就是依照principal-name来区分的)。
此外该注解还有个broadcast属性,表明是否广播。就是当有同一个用户登录多个session时,是否都能收到。取值true/false.
5.前端代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>接受消息</title>
</head>
<body>
</body>
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/sockjs.min.js"></script>
<script src="/static/js/stomp.js"></script>
<script th:inline="javascript">
var url=getUrl();
console.log(url);
var socket = new SockJS(url); //WebSocket对应的地址
stompClient = Stomp.over(socket);
var headers={
username:'admin',
password:'admin'
};
stompClient.connect(headers, function (frame) {
console.log('Connected: ' + frame);
//订阅AAA频道
stompClient.subscribe('/topic/AAA', function (greeting) {
//后台传过来的json字符串转换为json对象
console.log("AAA"+greeting);
});
//订阅BBB频道
stompClient.subscribe('/topic/BBB', function (greeting) {
//后台传过来的json字符串转换为json对象
console.log("BBB"+greeting);
//处理并显示数据
});
//订阅BBB频道
stompClient.subscribe('/topic/CCC', function (greeting) {
//后台传过来的json字符串转换为json对象
console.log("CCC"+greeting);
//处理并显示数据
});
});
//获取项目路径
function getUrl() {
var strFullPath=window.document.location.href;
var strPath=window.document.location.pathname;
var pos=strFullPath.indexOf(strPath);
var prePath=strFullPath.substring(0,pos);
var postPath=strPath.substring(0,strPath.substr(1).indexOf('/')+1);
var basePath = prePath+postPath;
var url=basePath+"//websocket/socketServer.action";
return url
}
</script>
</html>