websocket ,对于我来说已经是老朋友了。
很久很久以前,我写过两篇websocket 相关的文章。
一篇极简风,最最最基础的方式整合websocket :
《SpringBoot 整合WebSocket 简单实战案例》
地址: SpringBoot 整合WebSocket 简单实战案例_默默不代表沉默-CSDN博客_springboot websocket
一篇极限风,最最最完善的方式整合websocket (stomp+rabbitmq处理负载):
《Springboot 整合Websocket,Stomp协议,使用rabbitmq做消息代理,消息缓存》
地址: Springboot 整合Websocket+Stomp协议+RabbitMQ做消息代理 实例教程_默默不代表沉默-CSDN博客_rabbitmq stomp协议
然而那个极限的呢,又太复杂,看官们不乐意去整合rabbitmq。
那么,这篇文章的意义就出来了。
本篇内容:
1.后端整合websocket (STOMP协议)
2.群发、指定单发
3.前端简单页面示例(接收、发送消息)
事不宜迟,开始敲代码。
先看下这次实战案例项目结构:
1. pom.xml 核心依赖的导入:
org.springframework.boot
spring-boot-starter-websocket
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
2.application.yml (我就单纯设置一下端口)
server:
port: 9908
3.WebSocketConfig.java
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;
/**
* @Author JCccc
* @Description EnableWebSocketMessageBroker-注解开启STOMP协议来传输基于代理的消息,此时控制器支持使用@MessageMapping
* @Date 2021/6/30 8:53
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//topic用来广播,user用来实现点对点
config.enableSimpleBroker("/topic", "/user");
}
/**
* 开放节点
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//注册两个STOMP的endpoint,分别用于广播和点对点
//广播
registry.addEndpoint("/publicServer").setAllowedOrigins("*").withSockJS();
//点对点
registry.addEndpoint("/privateServer").setAllowedOrigins("*").withSockJS();
}
}
4.推送消息的实体类 Message.java
/**
* @Author JCccc
* @Description
* @Date 2021/8/20 9:26
*/
public class Message {
/**
* 消息编码
*/
private String code;
/**
* 来自(保证唯一)
*/
private String form;
/**
* 去自(保证唯一)
*/
private String to;
/**
* 内容
*/
private String content;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getForm() {
return form;
}
public void setForm(String form) {
this.form = form;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
5.前端简单调试页面
① publicExample.html 监听广播消息的测试页面
等系统推消息
连接广播频道
取消连接
广播消息
接收到的消息:
简析:
趁热打铁,我们模拟系统后端给前端推送广播消息,通过接口模拟:
TestController.java
/**
* @Author JCccc
* @Description
* @Date 2021/8/20 8:53
*/
@Controller
public class TestController {
@Autowired
public SimpMessagingTemplate template;
/**
* 广播
*
* @param msg
*/
@ResponseBody
@RequestMapping("/pushToAll")
public void subscribe( @RequestBody Message msg) {
template.convertAndSend("/topic/all", msg.getContent());
}
}
简析:
我们推送消息,直接用 SimpMessagingTemplate ,
用的是convertAndSend 广播方式推送到对于的主题目的地 destination 。
(可以看到其实还有convertAndSendToUser ,不着急,后面会说,这是发送给某个连接用户的)
可以看到实际上stomp.min.js 最终也是转化成为 ws/wss这种方式成功连接:
调用测试接口,推送广播消息:
在console其实也能看到:
广播功能就到这,接下来是 点对点。
前端页面:
privateExample.html
聊起来
连接用户
取消连接
发送消息
内容
发给谁
接收到的消息:
简析:
趁热打铁,我们模拟系统后端给前端推送点对点消息(指定某个用户),通过接口模拟:
/**
* 点对点
*/
@ResponseBody
@RequestMapping("/pushToOne")
public void queue(@RequestBody Message msg) {
System.out.println("进入方法");
/*使用convertAndSendToUser方法,第一个参数为用户id,此时js中的订阅地址为
"/user/" + 用户Id + "/message",其中"/user"是固定的*/
template.convertAndSendToUser(msg.getTo(), "/message", msg.getContent());
}
用的是convertAndSendToUser 推送到指定的用户 ,对于的主题目的地 destination(/message)
也许看到这里,你会觉得很奇怪,为什么我们推的主题是 /message,但是前端订阅的却是
"/user/" + 用户Id + "/message"
我们直接看源码:
ok,应该不用多说,代码帮我们自己拼接起来了,跟前端订阅规则保持一致。
直接跑项目,测试一下:
模拟我们连接的用户标识 19901 ,连接成功
使用postman调用我们的测试接口,模拟系统指定推送消息到 19901 这个人 :
然后看到对应的用户也能收到对应的消息:
对点推送,广播推送,也已经完毕了 。
这种情况就是相当于使用http接口方式,去撮合后端服务做 消息推送。
其实spring还提供了一些好玩的注解,
@MessageMapping 这个注解是对称于 @EnableWebSocketMessageBroker
也就是说,如果我们使用@EnableWebSocketMessageBroker ,那么我们在接口上面其实就能直接使用 @MessageMapping。
怎么用?
然后前端代码里面 的使用:
这样我们就可以通过前端直接调用相关接口了:
个人认为其实没有必要使用这个注解,直接通过前端调用后端服务代码,我们服务端来根据Message里面 的 发送方、接收方、消息类型(点对点、广播)就可以直接完成相关也业务场景了。
ok,该篇就到此。
下一篇,给大家带来怎么解决websocket负载问题 。