赞
踩
WebSocket是一种在Web浏览器和Web服务器之间建立实时双向通信的技术,它可以使客户端和服务器之间进行实时交互。
WebSocket让客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在pom.xml文件中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建一个类,并使用
@Component
注解将其声明为Spring Bean
。在该类中,需要实现WebSocketHandler
接口,并重写其中的方法来处理WebSocket
消息
@Component
public class MyWebSocketHandler implements WebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//连接成功时调用该方法
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
//接收到消息时调用该方法
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
//发生错误时调用该方法
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
//连接关闭时调用该方法
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
还可以自定义
WebSocketHandler
来处理WebSocket
消息。自定义WebSocketHandler
需要实现WebSocketHandler
接口,并重写其中的方法。
还可以继承以下类实现相关接口:
TextWebSocketHandler: 文本内容
BinaryWebSocketHandler:二进制内容
@Component
public class CustomizeWebSocketHandler extends TextWebSocketHandler {
private Logger log = LoggerFactory.getLogger(CustomizeWebSocketHandler.class);
private static final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info("与客户端建立连接...");
//连接成功时调用该方法
System.out.println("WebSocket connected: " + session.getId());
sessions.add(session);
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
// 获取客户端发送的消息
System.out.println("客户端ID: " + session.getId() + " 发送消息: " + message.getPayload());
for (WebSocketSession s : sessions) {
if (s.isOpen()) {
String response = "服务端响应: " + message.getPayload();
// 发送消息给客户端
s.sendMessage(new TextMessage(response));
// 关闭连接
// s.close(CloseStatus.NORMAL);
}
}
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
//发生错误时调用该方法
System.err.println("WebSocket error: " + exception.getMessage());
session.close(CloseStatus.SERVER_ERROR);
log.error("连接异常", exception);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
//连接关闭时调用该方法
System.out.println("WebSocket closed: " + session.getId());
sessions.remove(session);
super.afterConnectionClosed(session, closeStatus);
log.info("与客户端断开连接...");
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
WebSocketSession: 代表每个客户端会话,提供了许多实用方法
在 Spring Boot 应用程序的配置类中,创建
WebSocketServerConfigure配置类
,使用@EnableWebSocket
注解启用WebSocket支持。然后需要实现WebSocketConfigurer
接口,将自定义的CustomizeWebSocketHandler
注册到Spring Boot容器并设置拦截路径/webSocket
,凡是该路径请求的连接将自动连接到WebSocket服务端。
@Configuration
@EnableWebSocket//开启WebSocket相关功能
public class WebSocketServerConfigure implements WebSocketConfigurer {
@Autowired
private CustomizeWebSocketHandler customizeWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册自定义customizeWebSocketHandler 使用sockJs
registry.addHandler(customizeWebSocketHandler, "/sockJs").withSockJS();
// 注册自定义customizeWebSocketHandler 使用ws
registry.addHandler(customizeWebSocketHandler, "/ws").setAllowedOrigins("*");
}
}
WebSocket是一种基于TCP协议的全双工通信协议,在Web应用中可以实现双向通信。浏览器可以使用WebSocket对象与服务端建立连接,并通过该连接来接收服务端发送的消息,从而实现页面代码对服务端的通知。
创建index.html
页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket客户端</title>
</head>
<body>
<div style="width:50%;margin:auto;border-style:solid;border-color:aqua;border-width: 1px">
<input type="text" placeholder="请输入发送的内容" id="text"/>
<input type="button" value="连接" class="btn btn-info" onclick="connect()"/>
<input type="button" value="发送" class="btn btn-success" onclick="sent()"/>
<input type="button" value="断开" class="btn btn-danger" onclick="disconnect()"/>
<div id="log">
<p>聊天记录:</p>
</div>
</div>
<script type="text/javascript">
let text = document.querySelector('#text');
let logDiv = document.querySelector("#log");
let ws = null;
function connect() {
ws = new WebSocket("ws://localhost:8080/ws");
ws.onopen = function () {
log('与服务端连接成功!');
};
ws.onmessage = function (event) {
log('服务端:' + event.data);
};
ws.onclose = function () {
log('与服务端断开连接!')
}
}
function sent() {
if (ws != null) {
ws.send(text.value);
log('客户端:' + text.value);
} else {
log('请先建立连接!')
}
}
function disconnect() {
if (ws != null) {
ws.close();
ws = null;
} else {
log('连接已断开!')
}
}
function log(value) {
let content = document.createElement('p');
content.innerHTML = value;
logDiv.appendChild(content);
text.value = '';
}
</script>
</body>
</html>
跳转到index.html页面
@Controller
public class TestController {
@RequestMapping("/index")
public String index() {
return "index";
}
}
SockJS是一个WebSocket的封装库,它提供了一种简单的方式来处理WebSocket在某些浏览器中无法正常工作的情况。通常,当WebSocket不可用时,SockJS会自动降级到使用HTTP流等其他技术进行实现。
SockJS: https://github.com/sockjs/sockjs-client
SockJS对象包含几个常用的实用方法:
onopen,和服务端讲了连接后的回调方法
onmessage,服务端返回消息时的回调方法
onclose,和服务端断开连接的回调方法
send,发送消息给服务端
close,断开和服务端的连接
引入SockJS库。在connect()方法中,通过new SockJS(/connect)和服务端建立Socket通信
<head>
<meta charset="UTF-8">
<title>WebSocket客户端</title>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
</head>
使用SockJS对象
let url = "http://localhost:8080/sockJs";
ws = new SockJS(url);
WebSocket日志
2023-05-21 21:07:40.182 INFO 28400 --- [nio-8080-exec-2] c.y.demo.ws.CustomizeWebSocketHandler : 与客户端建立连接...
WebSocket connected: 5442a838-e6f7-fdff-3eef-004732be1bb2
客户端ID: 5442a838-e6f7-fdff-3eef-004732be1bb2 发送消息: 你好
WebSocket closed: 5442a838-e6f7-fdff-3eef-004732be1bb2
2023-05-21 21:07:45.885 INFO 28400 --- [nio-8080-exec-7] c.y.demo.ws.CustomizeWebSocketHandler : 与客户端断开连接...
SockJS日志
2023-05-21 21:11:42.962 INFO 9980 --- [nio-8080-exec-3] c.y.demo.ws.CustomizeWebSocketHandler : 与客户端建立连接...
WebSocket connected: dnf1qgco
客户端ID: dnf1qgco 发送消息: 123
WebSocket closed: dnf1qgco
2023-05-21 21:11:47.419 INFO 9980 --- [nio-8080-exec-5] c.y.demo.ws.CustomizeWebSocketHandler : 与客户端断开连接...
还可以使用@ServerEndpoint注解来创建WebSocket服务器端点。这个注解将类标记为一个WebSocket服务器端点,并定义了客户端连接的URL路径,例如:/ws/socket
@OnOpen、@OnClose和@OnMessage注解分别表示连接建立、连接关闭和接收消息时要执行的方法。
当客户端连接到服务器时,onOpen方法将被调用,并且将传递Session对象作为参数。通过Session对象,可以发送消息给客户端
当客户端发送消息时,onMessage方法将被调用,并且将传递消息和Session对象作为参数。可以在其中实现业务逻辑,例如广播消息给所有连接的客户端
当客户端断开连接时,onClose方法将被调用
@Slf4j
@Component
@ServerEndpoint(value = "/ws/socket")
public class WebSocketServer {
// 使用一个ConcurrentSkipListSet集合来保存所有连接的WebSocket客户端。这个集合是线程安全的,可以安全地从多个线程访问
private static Map<String, Session> sessionPools = new ConcurrentHashMap<>();
/**
* 连接建立成功调用
*
* @param session 客户端与socket建立会话
*/
@OnOpen
public void onOpen(Session session) {
log.info("有新的WebSocket连接:" + session.getId());
// 添加新连接到集合中
sessionPools.put(session.getId(), session);
}
/**
* 获取所有在线用户列表
*
* @return
*/
public List<String> getInLineAccountIds() {
List<String> list = new ArrayList();
list.addAll(sessionPools.keySet());
return list;
}
@OnMessage
public void onMessage(Session session, String message) {
log.info("接收到WebSocket消息:" + message);
sendMessage(session, message);
}
/**
* 关闭连接时调用
*
* @param session 关闭连接的客户端的姓名
*/
@OnClose
public void onClose(Session session) {
sessionPools.remove(session.getId());
// 从集合中删除断开的连接
log.info("WebSocket连接已关闭:" + session.getId());
}
/**
* 发生错误时候
*
* @param session
* @param throwable
*/
@OnError
public void onError(Session session, Throwable throwable) {
log.info("发生错误");
sessionPools.remove(session.getId());
throwable.printStackTrace();
}
/**
* 发送消息
*
* @param session
* @param message
*/
private void sendMessage(Session session, String message) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 给指定用户发送消息
*
* @throws IOException
*/
public void pushMessage(String sessionId, String msg) {
//获取当前会话
Session session = sessionPools.get(sessionId);
if (null != session) {
//获取消息体
sendMessage(session, msg);
}
}
}
/**
* 开启WebSocket支持
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
建立WebSocket链接
ws = new WebSocket("ws://localhost:8080/ws/socket");
日志
2023-05-21 21:59:48.100 INFO 31752 --- [nio-8080-exec-2] cn.ybzy.demo.ws.WebSocketServer : 有新的WebSocket连接:0
session = org.apache.tomcat.websocket.WsSession@7100dfaf
2023-05-21 22:00:21.287 INFO 31752 --- [nio-8080-exec-7] cn.ybzy.demo.ws.WebSocketServer : 接收到WebSocket消息:你好
2023-05-21 22:00:24.706 INFO 31752 --- [nio-8080-exec-8] cn.ybzy.demo.ws.WebSocketServer : WebSocket连接已关闭:0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。