Spring Boot 使用STOMP实现WebSocket

WebSocket 与 STOMP 协议

WebSocket 是在TCP上分层的全双工(允许数据在两个方向上同时传输)通信协议,它允许你在应用程序直接双向通信,通常用于浏览器和服务器之间的交互通信。它最大的特点就是服务器可以主动向客户端(浏览器)推送消息,客户端也可以主动向服务器发送消息。

Spring Boot 使用STOMP实现WebSocket

STOMP 是一种基于文本的简单消息传递协议,任何 STOMP 客户端都可以与任何 STOMP 消息代理进行通信。与 WebSocket 不同的是, STOMP 描述了客户端和服务器之间交换的消息格式,而 WebSocket 是一种通信协议。我们不能仅使用 STOMP 与服务器或消息代理通信,我们必须使用传输方式发送 STOMP 消息,其中之一就是 WebSocket。仅使用 WebSocket 也很难实现仅向订阅了特定主题的用户发送消息的功能,但是 STOMP 具有这些功能,因为它本来就是用来与消息代理进行交互的。因此两者搭配使用可以更快速简单的实现功能。

服务端配置

添加 Maven 依赖

pom.xml

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

创建 DTO

新建类 MessageResult ,用于返回前端;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
publicclassMessageResult{
+
publicMessageResult(){
}

publicMessageResult(String content){
this.content = content;
}

private String content;

public String getContent(){
return content;
}

publicvoidsetContent(String content){
this.content = content;
}
}

新建类 MessageParam ,用于接收前端参数;

1
2
3
4
5
6
7
8
9
10
11
12
publicclassMessageParam{

private String content;

public String getContent(){
return content;
}

publicvoidsetContent(String content){
this.content = content;
}
}

创建控制器 Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import cn.hutool.core.date.DateUtil;
import com.lanweihong.hotel.pms.bean.MessageParam;
import com.lanweihong.hotel.pms.bean.MessageResult;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;

/**
* @author lanweihong
*/
@Controller
publicclassWebSocketController{

@MessageMapping("/hello")
@SendTo("/topic/messages")
public MessageResult test(@RequestBody MessageParam message){
returnnew MessageResult(DateUtil.now() + ":" + message.getContent());
}
}

创建 WebSocket 配置类,用于 STOMP 消息传递

新建类 WebSocketConfig 用于配置 Spring 以启用 WebSocketSTOMP 消息传递;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
import org.springframework.messaging.simp.config.ChannelRegistration;
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;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;

import java.util.List;

/**
* @author lanweihong
*/
@Configuration
@EnableWebSocketMessageBroker
publicclassWebSocketConfigimplementsWebSocketMessageBrokerConfigurer{

@Override
publicvoidconfigureWebSocketTransport(WebSocketTransportRegistration webSocketTransportRegistration){

}

@Override
publicvoidconfigureClientInboundChannel(ChannelRegistration channelRegistration){

}

@Override
publicvoidconfigureClientOutboundChannel(ChannelRegistration channelRegistration){

}

@Override
publicvoidaddArgumentResolvers(List<HandlerMethodArgumentResolver> list){

}

@Override
publicvoidaddReturnValueHandlers(List<HandlerMethodReturnValueHandler> list){

}

@Override
publicbooleanconfigureMessageConverters(List<MessageConverter> list){
returnfalse;
}

@Override
publicvoidconfigureMessageBroker(MessageBrokerRegistry config){
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}

@Override
publicvoidregisterStompEndpoints(StompEndpointRegistry registry){
registry.addEndpoint("/broadcast").withSockJS();
}
}

@EnableWebSocketMessageBroker 表示启用由消息代理支持的WebSocket消息处理;

方法 configureMessageBroker() 实现 WebSocketMessageBrokerConfigurer 用于配置消息代理的默认方法,首先调用 enableSimpleBroker() 来启用一个简单的基于内存的消息代理,将请求消息发送到目的地 /topic ;并设置应用程序目标前缀为 /app,此前缀将用于定义所有消息映射,如 /app/message 端点则会调用 WebSocketTestController.test() 方法;

方法 registerStompEndpoints() 注册 /broadcast 端点;启用SockJS后备选项,以便在 WebSocket 不可用时可以使用备用传输。

前端客户端使用

安装插件

1
2
npm install sockjs-client
npm install stompjs

编写页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template>
<divclass="websocket-test-container whui-router-view-container">
<divclass="form-wrapper">
<Inputtype="text"v-model="form.message"placeholder="消息内容"></Input>
</div>
<divclass="action">
<Buttontype="primary" @click="connectSocket">连接</Button>
<Buttontype="info" @click="disconnectSocket">关闭连接</Button>
<Buttontype="error" @click="sendMessage">发送</Button>
</div>
<divclass="message-content">
<divclass="message-list">
<ul>
<liv-for="item in messageList":key="item.content">
{{item.content}}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import SockJS from'sockjs-client'
import Stomp from'stompjs'
exportdefault {
data () {
return {
form: {
message: ''
},
stompClient: null,
messageList: []
}
},
methods: {
connectSocket () {
// 连接
let socket = new SockJS('http://127.0.0.1:8091/broadcast')
// 获取 STOMP 子协议的客户端对象
this.stompClient = Stomp.over(socket)
// 发起 websocket 连接
this.stompClient.connect({}, (frame) => {
// 订阅 topic
this.stompClient.subscribe('/topic/messages', (res) => {
console.log(JSON.stringify(res.body))
this.messageList.push(JSON.parse(res.body))
})
})
},
disconnectSocket () {
if (this.stompClient != null) {
this.stompClient.disconnect()
}
},
sendMessage () {
let data = {
content: this.form.message
}
let dataStr = JSON.stringify(data)
this.stompClient.send('/app/hello', {}, dataStr)
}
}
}
</script>
<stylelang="stylus">
li
list-style none
.websocket-test-container
padding 20px
.message-list
padding-top 10px
.form-wrapper
padding-bottom 10px
</style>

运行测试

页面效果

Spring Boot 使用STOMP实现WebSocket

单击 连接 后,请求标头内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
GET ws://127.0.0.1:8091/broadcast/616/g1jm4jnu/websocket HTTP/1.1
Host: 127.0.0.1:8091
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36
Upgrade: websocket
Origin: http://127.0.0.1:8080
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7
Sec-WebSocket-Key: 8koVldvnTgAED1I1TXR+hQ==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

响应标头内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP/1.1101
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://127.0.0.1:8080
Access-Control-Allow-Credentials: true
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: 7nqt8KuROUFLlDZbt8XgE4XooOE=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Date: Wed, 28 Oct 202010:14:56 GMT

在文本框中输入消息,单击 发送 ,可查看消息内容:

Spring Boot 使用STOMP实现WebSocket

参考:

Using WebSocket to build an interactive web application

Using Spring Boot for WebSocket Implementation with STOMP

以上是 Spring Boot 使用STOMP实现WebSocket 的全部内容, 来源链接: utcz.com/a/131083.html

回到顶部