WebSocket 协议主要用来实现后台服务端主动向客户端推送消息,当然,协议本身支持双向通信。
在 Spring 项目中集成 WebSocket 还是比较简单的,但是 WebSocket 的 Session 和 HttpSession 并不相通,如果想获取 HttpSession 中的登录用户就要稍费工夫,因此,记录成篇。
一、集成 WebSocket
- 项目添加依赖包:
1
2
3
4
5<!-- SpringBoot Websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency> - 增加 WebSocketConfig 配置类:
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* websocket 配置
*
* @author xhp
*/
public class WebSocketConfig {
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
} - 编写 WebSocketSever 类:
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
public class WebSocketServer {
/**
* 连接建立成功调用的方法
*/
public void onOpen(Session session) throws Exception {
}
/**
* 连接关闭时处理
*/
public void onClose(Session session) {
}
/**
* 抛出异常时处理
*/
public void onError(Session session, Throwable exception) throws Exception {
if (session.isOpen()) {
// 关闭连接
session.close();
}
}
/**
* 服务器接收到客户端消息时调用的方法
*/
public void onMessage(String message, Session session) {
}
} - 编写 html 页面,测试连接:
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<script type="text/javascript">
$(document).ready(function(){
// WebSocket
var wsBaseUrl = /*[[${"ws://" + #httpServletRequest.getServerName() + ":" + #httpServletRequest.getServerPort() + #httpServletRequest.getContextPath()}]]*/'';
var ws = new WebSocket(wsBaseUrl + '/ws/message');
ws.onopen = function (event) {
console.log('WS 已打开连接 ');
}
ws.onmessage = function (event) {
// TODO 接收消息
console.log(event.data);
}
ws.onclose = function (event) {
console.log('WS 已关闭连接 ');
}
// 发送消息
$('#btn_send').click(function() {
var message = $('#message').val();
if (ws) {
ws.send(message);
} else {
alert(" 未连接到服务器 ");
}
});
// 断开
$('#btn_exit').click(function() {
if (ws) {
ws.close();
ws = null;
}
});
})
</script>
二、WebSocket 会话获得登录用户
场景说明:
- 项目中常见场景,需要给某个用户或者某类用户推送消息;
- 我们需要在全部的 WebSocket 连接会话里根据登录用户匹配有效的发送会话;
- 因为 WebSocket 的 Session 和 HttpSession 是相互独立的,本身没用对应关系,那么,我们只能想办法把需要的信息放到 Session 里。
修改 WebSocketConfig 配置类,重写其继承类的方法,将用户信息放入,示例如下:
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
27import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
/**
* websocket 配置
*
* @author xhp
*/
public class WebSocketConfig extends ServerEndpointConfig.Configurator {
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
// 将用户信息存储到 socket 的配置里
sec.getUserProperties().put("sysUser", ShiroUtils.getSysUser());
super.modifyHandshake(sec, request, response);
}
}修改 WebSocketServer 类,读取用户信息,示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/**
* websocket 消息处理
*
* @author xhp
*/
public class WebSocketServer {
/**
* 连接建立成功调用的方法
*/
public void onOpen(Session session) throws Exception {
// 读取用户信息
SysUser sysUser= (SysUser)session.getUserProperties().get("sysUser");
}
}
三、注意事项
- 本示例项目是 Springboot,如果项目是 Spring 而非 Springboot,那么第一步的依赖包有所不同,后面的步骤是一致的;
WebSocketServer类的类注解需要增加对配置文件的引入configurator = WebSocketConfig.class,否则配置文件的重写方法是不生效的;
原文链接: https://xinghuipeng.pages.dev/2022/11/11/work/java/Spring集成WebSocket/
版权声明: 转载请注明出处.