您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Spring Boot 中如何使用WebSocket
## 1. WebSocket 简介
### 1.1 什么是WebSocket
WebSocket是一种在单个TCP连接上进行全双工通信的协议,它允许服务端主动向客户端推送数据。与传统的HTTP请求-响应模式不同,WebSocket提供了持久化的连接,使得客户端和服务器之间的数据交换变得更加高效。
### 1.2 WebSocket与HTTP的区别
| 特性 | WebSocket | HTTP |
|---------------|-------------------------------|--------------------------|
| 通信模式 | 全双工 | 半双工(请求-响应) |
| 连接持续时间 | 持久化 | 短暂(每次请求后关闭) |
| 头部开销 | 初始握手后基本无头部 | 每次请求都携带完整头部 |
| 适用场景 | 实时应用(聊天、游戏等) | 传统网页内容获取 |
### 1.3 WebSocket的应用场景
- 实时聊天应用
- 在线协作编辑工具
- 多人在线游戏
- 股票行情实时推送
- IoT设备状态监控
## 2. Spring Boot集成WebSocket
### 2.1 添加依赖
在`pom.xml`中添加以下依赖:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建配置类启用WebSocket支持:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/ws")
.setAllowedOrigins("*");
}
@Bean
public WebSocketHandler myHandler() {
return new MyWebSocketHandler();
}
}
创建自定义处理器处理消息:
public class MyWebSocketHandler extends TextWebSocketHandler {
private static final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
System.out.println("New connection: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
String payload = message.getPayload();
System.out.println("Received: " + payload);
// 广播消息给所有客户端
for (WebSocketSession s : sessions) {
try {
s.sendMessage(new TextMessage("Echo: " + payload));
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
System.out.println("Connection closed: " + session.getId());
}
}
添加STOMP子协议支持:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-stomp")
.setAllowedOrigins("*")
.withSockJS();
}
}
当浏览器不支持WebSocket时,SockJS会自动降级使用其他技术:
registry.addEndpoint("/ws")
.withSockJS();
实现握手拦截器:
public class AuthHandshakeInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) {
// 验证逻辑
return true; // 返回false拒绝连接
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception) {
}
}
注册拦截器:
registry.addHandler(myHandler(), "/ws")
.addInterceptors(new AuthHandshakeInterceptor());
const socket = new WebSocket('ws://localhost:8080/ws');
socket.onopen = () => {
console.log('Connected');
socket.send('Hello Server!');
};
socket.onmessage = (event) => {
console.log('Received: ' + event.data);
};
socket.onclose = () => {
console.log('Disconnected');
};
使用WebSocketClient
:
WebSocketClient client = new StandardWebSocketClient();
WebSocketSession session = client.doHandshake(
new WebSocketHandler() { /*...*/ },
"ws://localhost:8080/ws"
).get();
registry.setMessageSizeLimit(128 * 1024); // 128KB
解决方案: - 使用Redis广播消息
@Configuration
@EnableRedisRepositories
public class RedisConfig {
@Bean
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory factory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
return container;
}
}
@Controller
public class ChatController {
@MessageMapping("/chat.send")
@SendTo("/topic/public")
public ChatMessage sendMessage(@Payload ChatMessage message) {
return message;
}
@MessageMapping("/chat.join")
@SendTo("/topic/public")
public ChatMessage join(@Payload ChatMessage message,
SimpMessageHeaderAccessor headerAccessor) {
headerAccessor.getSessionAttributes().put("username", message.getSender());
return message;
}
}
<div id="chat">
<input type="text" id="message" />
<button onclick="send()">Send</button>
<div id="messages"></div>
</div>
<script>
const stompClient = new StompJs.Client({
brokerURL: 'ws://localhost:8080/ws-stomp'
});
stompClient.onConnect = () => {
stompClient.subscribe('/topic/public', (message) => {
showMessage(JSON.parse(message.body));
});
};
function send() {
const message = document.getElementById('message').value;
stompClient.publish({
destination: '/app/chat.send',
body: JSON.stringify({'content': message})
});
}
</script>
@SpringBootTest
class WebSocketTests {
@Autowired
private WebSocketHandler handler;
@Test
void testMessageHandling() throws Exception {
TestWebSocketSession session = new TestWebSocketSession();
handler.afterConnectionEstablished(session);
TextMessage message = new TextMessage("test");
handler.handleMessage(session, message);
assertEquals(1, session.getSentMessages().size());
}
}
暴露WebSocket统计信息:
@Bean
public WebSocketMetrics webSocketMetrics() {
return new WebSocketMetrics();
}
spring-boot-starter-websocket
简化集成附录:完整配置示例
@Configuration
@EnableWebSocketMessageBroker
public class FullWebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("rabbitmq-host")
.setRelayPort(61613);
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-full")
.setHandshakeHandler(new CustomHandshakeHandler())
.addInterceptors(new AuthInterceptor())
.setAllowedOrigins("*")
.withSockJS();
}
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
registry.setMessageSizeLimit(512 * 1024)
.setSendTimeLimit(10000)
.setSendBufferSizeLimit(1024 * 1024);
}
}
”`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。