WebSocket 是一种在客户端和服务器之间提供低延迟、全双工通信的网络协议。它允许双方在建立一次连接后,进行实时、持续的数据交换,无需像HTTP那样为每一个请求和响应建立新的连接。WebSocket的设计初衷是解决传统HTTP协议在实时通信方面的不足,比如实现实时聊天、游戏、股票报价等需要高频率、连续数据更新的应用场景。
1 构建服务端
1.1 引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
1.2 创建配置类
@Slf4j
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
1.3 创建服务端
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocketTest {/*** 线程安全的无序的集合*/private static final CopyOnWriteArraySet<Session> SESSIONS = new CopyOnWriteArraySet<>();/*** 存储在线连接数*/private static final Map<String, Session> SESSION_POOL = new HashMap<>();@OnOpenpublic void onOpen(Session session, @PathParam(value = "userId") String userId) {try {SESSIONS.add(session);SESSION_POOL.put(userId, session);log.info("【WebSocket消息】有新的连接,总数为:" + SESSIONS.size());} catch (Exception e) {e.printStackTrace();}}@OnClosepublic void onClose(Session session) {try {SESSIONS.remove(session);log.info("【WebSocket消息】连接断开,总数为:" + SESSIONS.size());} catch (Exception e) {e.printStackTrace();}}@OnMessagepublic void onMessage(String message) {log.info("【WebSocket消息】收到客户端消息:" + message);Session session = SESSION_POOL.get("123");if (session != null && session.isOpen()) {try {synchronized (session) {log.info("【WebSocket消息】单点消息:" + message);session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}/*** 此为广播消息** @param message 消息*/public void sendAllMessage(String message) {log.info("【WebSocket消息】广播消息:" + message);for (Session session : SESSIONS) {try {if (session.isOpen()) {session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}/*** 此为单点消息** @param userId 用户编号* @param message 消息*/public void sendOneMessage(String userId, String message) {Session session = SESSION_POOL.get(userId);if (session != null && session.isOpen()) {try {synchronized (session) {log.info("【WebSocket消息】单点消息:" + message);session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}/*** 此为单点消息(多人)** @param userIds 用户编号列表* @param message 消息*/public void sendMoreMessage(String[] userIds, String message) {for (String userId : userIds) {Session session = SESSION_POOL.get(userId);if (session != null && session.isOpen()) {try {log.info("【WebSocket消息】单点消息:" + message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}
}
2 创建客户端
2.1 引入依赖
<dependency><groupId>org.java-websocket</groupId><artifactId>Java-WebSocket</artifactId><version>1.5.3</version>
</dependency>
2.2 注入对象
在配置类中注入WebSocketClient
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;import java.net.URI;@Slf4j
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}@Beanpublic WebSocketClient webSocketClient() {WebSocketClient wsc = null;try {wsc = new WebSocketClient(new URI("ws://127.0.0.1:2580/websocket/123")) {@Overridepublic void onOpen(ServerHandshake serverHandshake) {log.info("与服务端建立连接");}@Overridepublic void onMessage(String s) {log.info("收到服务端的消息:{}", s);}@Overridepublic void onClose(int i, String s, boolean b) {log.info("与服务端的连接断开 code:{} reason:{} {}", i, s, b);}@Overridepublic void onError(Exception e) {log.info("连接报错");}};wsc.connect();return wsc;} catch (Exception e) {e.printStackTrace();}return wsc;}
}
2.3 测试
import org.java_websocket.client.WebSocketClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
public class TestController {@ResourceWebSocketClient wsClient;@GetMapping("/send")public void test(String text){wsClient.send(text);}
}
2.4 结果
浏览器访问
http://localhost:2580/send?text=测试
结果
2024-07-06 15:38:28.586 INFO 25860 --- [nio-2580-exec-4] c.x.p.websocket.socket.WebSocketTest : 【WebSocket消息】收到客户端消息:测试
2024-07-06 15:38:28.586 INFO 25860 --- [nio-2580-exec-4] c.x.p.websocket.socket.WebSocketTest : 【WebSocket消息】单点消息:测试
2024-07-06 15:38:28.587 INFO 25860 --- [ctReadThread-31] c.x.p.websocket.config.WebSocketConfig : 收到服务端的消息:测试