在 WebSocket通信 简单介绍了下WebSocket,提到WebSocket其实是一种协议规范,在实际的实现中有WebSocket的子协议STOMP 和 HTML5规范中的WebSocket API。
这里我们就先来介绍一些STOMP协议的实际运行,首先我们先来简单了解一下STOMP:
- 简单(流)文本定向消息协议
- STOMP协议的前身是TTMP协议(一个简单的基于文本的协议),专为消息中间件设计。是属于消息队列的一种协议, 和AMQP, JMS平级. 它的简单性恰巧可以用于定义websocket的消息体格式. STOMP协议很多MQ都已支持, 比如RabbitMq, ActiveMq。
- 生产者(发送消息)、消息代理、消费者(订阅然后收到消息)
- STOMP是基于帧的协议
这里我们就利用Stomp的实际运用来完成一个简单的聊天工具的使用,一个简单的聊天工具一般都分为群聊和私聊,其实现示意图如下:
首先我们新建一个SpringBoot的项目,然后就先引入我们在浏览器使用WebSocket必须的几个js工具包,其项目结构如下:
接下来先在pom.xml引入我们需要使用的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
然后 ChatApplication 类就是标准的SpringBoot启动类,没什么好说的
@SpringBootApplication
public class ChatApplication {
public static void main(String[] args) {
SpringApplication.run(ChatApplication.class, args);
}
}
这里我们还定义了一个 ChatContent 类,就是用户封装用户发送及接受消息的JavaBean,这里业务较为简单,就用了一个类来接受与响应了,在业务复杂的情况下,比如可以分为Request和Response等等。
public class ChatContent {
private String sender; //消息发送者
private String content; //消息内容
private String receiver; //消息接受者
//省略Getter、Setter方法
...
}
接下来我们看一下config文件夹下的配置类,首先是 WebMvcConfig 配置类,也是十分的简单,就是设置我们在访问 /chat
路径的时候,进行访问 chat.html
文件
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/chat").setViewName("/chat");
}
}
上述写法其作用和我们之前在SpringMVC中的Controller写法是一致的,如我们可以在 ChatController 中设置用于取代上述配置类,如下:
@RequestMapping("/chat")
private String chat(){
return "chat";
}
另外一个 WebSocketConfig 配置类,就需要结合我们之前的业务流程示意图进行查看了
@Configuration
//开启使用Stomp协议来传输基于消息broker的消息
//开启后控制器支持使用@MessageMapping,类似使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/endpointChat") //注册STOMP协议的节点(Endpoint),并映射指定的url,
//添加一个访问路径 "/endpointChat", 客户端打开双通道时需要的url
.setAllowedOrigins("*") //允许所有的域名跨域访问
.withSockJS(); //指定使用SockJS协议
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//配置消息代理,group表示群聊,private表示私聊
registry.enableSimpleBroker("/group", "/private");
//私聊时,请求将发送到该路径下
registry.setUserDestinationPrefix("/private");
}
}
上述代码类中的第一个重写的方法,就是我们浏览器向服务器发起连接请求时的节点(Endpoint),第二个重写的方法就是用于浏览器在连接成功后,向浏览器发出的订阅请求
接下来就是我们的 ChatController 类了,就两个方法,一个负责消息群发,一个负责消息私聊,其中@MessageMapping注解就是我们在WebSocketConfig配置类上开启了@EnableWebSocketMessageBroker才可以使用的,这里作用类似于@RequestMapping注解
@Controller
public class ChatController {
@Autowired
private SimpMessagingTemplate template; //Spring中实现的模板类
//消息群发
@MessageMapping("/groupMsgHandler") //接收处理发送至 groupMsgHandler 下的请求
@SendTo("/group/response") //指定发送至Broker下的指定订阅路径 /group,
//Broker再根据/response发送消息到订阅了/group/response的用户出
public ChatContent group(ChatContent content){
System.out.println(content);
return content;
}
//私聊
@MessageMapping("/privateMsgHandler")
public ChatContent privateMsg(ChatContent content){
System.out.println(content);
this.template.convertAndSendToUser(content.getReceiver(), "/chat", content);
return content;
}
}
其中消息群发方法上还有一个@SendTo注解,该注解就是将接收到的信息,经过业务处理之后return返回的值,发送给订阅了/group/response
的用户,该前缀 /group
也是我们在WebSocketConfig配置类中进行配置的
私聊方法上就没有了@SendTo注解,这里我们使用的SimpMessagingTemplate模板,它将消息发送给订阅了我们拼凑出的路径的用户,该路径前面会加上配置类WebSocketConfig中的/private
路径,我们还可以使用@SendToUser注解来代替
剩下的就是我们的前端页面及逻辑的,其实也是非常简单,看完服务端代码,我们肯定知道,我们需要订阅两个消息,用于接受别人群发和私聊的信息,还有就是我们的群发消息和私聊别人的时候,只需将内容发送到指定的路径下即可。
首先我们浏览器加载完成后,就自动连接WebSocket服务端,连接成功后就订阅群发消息,我们大致查看下 chat.js 的内容及主要功能:
在接受到消息后,就将其展示出来,就是一个很简单的html页面
群发消息可以接受了,那么我们来看一下如何发送群消息,在页面上我们设置了一个下拉框,里面固定了几个用户,我们可以选择一个用户就可以进行发送消息了
这样群发消息,和接受群消息就完成了,另外私聊的原理也是一样,我们只需要加上接收人即可,如下:
最后我们简单看一下html页面,然后运行我们的程序,查看其效果
运行截图如下: