package com.ruoyi.web.controller.webSocket; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.springframework.boot.test.context.SpringBootTest; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * WebSocket客户端测试类 * 演示如何连接WebSocket服务端并进行认证 */ @SpringBootTest @Slf4j public class WebSocketClientTest { private static final String WEBSOCKET_URL = "ws://127.0.0.1:8888/hello"; private static final String TEST_USER_ID = "1964941649976532994"; private static final String TEST_TOKEN = "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2FwcGxldF9rZXkiOiJhMzkyMTdmZS1hZmRiLTQ1YTAtYjkwMy01MGViNjc4ZGJlNzAifQ.SaLnyIsAQ9lnSivaXPaO71gReSmx-R_tjrS3auKJqbXKe2SiLr7MZiNetdjmwvE7HSzjxs1yTqVW9mXGcAuWHw"; /** * 测试WebSocket连接和认证 */ @Test public void testWebSocketConnection() throws Exception { CountDownLatch latch = new CountDownLatch(1); // 创建WebSocket客户端 SimpleWebSocketClient client = new SimpleWebSocketClient(WEBSOCKET_URL, new WebSocketClient.MessageHandler() { @Override public void onOpen() { log.info("WebSocket连接已建立"); // 发送认证消息 sendAuthMessage(); } @Override public void onMessage(String message) { log.info("收到服务器消息: {}", message); try { JSONObject messageObj = JSON.parseObject(message); String messageType = messageObj.getString("type"); switch (messageType) { case "auth_success": log.info("认证成功: {}", messageObj.getString("message")); // 认证成功后发送业务消息 sendBusinessMessage(); break; case "auth_failed": log.error("认证失败: {}", messageObj.getString("message")); break; case "pong": log.info("收到心跳响应"); break; case "message_response": log.info("收到业务消息响应: {}", messageObj.getString("originalMessage")); break; default: log.info("收到其他消息: {}", message); } } catch (Exception e) { log.error("解析消息失败: {}", e.getMessage()); } } @Override public void onClose(int code, String reason) { log.info("WebSocket连接已关闭: code={}, reason={}", code, reason); latch.countDown(); } @Override public void onError(Exception e) { log.error("WebSocket连接错误: {}", e.getMessage(), e); latch.countDown(); } }); // 连接WebSocket client.connect(); // 等待连接关闭 latch.await(30, TimeUnit.SECONDS); // 关闭连接 client.close(); } /** * 测试无Token认证 */ @Test public void testWebSocketConnectionWithoutToken() throws Exception { CountDownLatch latch = new CountDownLatch(1); SimpleWebSocketClient client = new SimpleWebSocketClient(WEBSOCKET_URL, new WebSocketClient.MessageHandler() { @Override public void onOpen() { log.info("WebSocket连接已建立(无Token)"); sendAuthMessageWithoutToken(); } @Override public void onMessage(String message) { log.info("收到服务器消息: {}", message); handleMessage(message); } @Override public void onClose(int code, String reason) { log.info("WebSocket连接已关闭: code={}, reason={}", code, reason); latch.countDown(); } @Override public void onError(Exception e) { log.error("WebSocket连接错误: {}", e.getMessage(), e); latch.countDown(); } }); client.connect(); latch.await(10, TimeUnit.SECONDS); client.close(); } /** * 测试心跳功能 */ @Test public void testWebSocketHeartbeat() throws Exception { CountDownLatch latch = new CountDownLatch(1); SimpleWebSocketClient client = new SimpleWebSocketClient(WEBSOCKET_URL, new WebSocketClient.MessageHandler() { @Override public void onOpen() { log.info("WebSocket连接已建立"); sendAuthMessage(); } @Override public void onMessage(String message) { log.info("收到服务器消息: {}", message); try { JSONObject messageObj = JSON.parseObject(message); String messageType = messageObj.getString("type"); if ("auth_success".equals(messageType)) { log.info("认证成功,开始发送心跳"); // 认证成功后开始发送心跳 startHeartbeat(); } else if ("pong".equals(messageType)) { log.info("收到心跳响应"); } } catch (Exception e) { log.error("解析消息失败: {}", e.getMessage()); } } @Override public void onClose(int code, String reason) { log.info("WebSocket连接已关闭: code={}, reason={}", code, reason); latch.countDown(); } @Override public void onError(Exception e) { log.error("WebSocket连接错误: {}", e.getMessage(), e); latch.countDown(); } }); client.connect(); latch.await(30, TimeUnit.SECONDS); client.close(); } /** * 发送认证消息 */ private void sendAuthMessage() { JSONObject authMessage = new JSONObject(); authMessage.put("type", "auth"); authMessage.put("appUserId", TEST_USER_ID); authMessage.put("token", TEST_TOKEN); String message = authMessage.toJSONString(); log.info("发送认证消息: {}", message); // 这里需要实际的WebSocket客户端实现 } public static void main(String[] args) { // 发送认证消息: {"deviceType":"test","type":"auth","appUserId":"1964941649976532994","deviceId":"test-device-1761294213830","token":"eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2FwcGxldF9rZXkiOiJhMzkyMTdmZS1hZmRiLTQ1YTAtYjkwMy01MGViNjc4ZGJlNzAifQ.SaLnyIsAQ9lnSivaXPaO71gReSmx-R_tjrS3auKJqbXKe2SiLr7MZiNetdjmwvE7HSzjxs1yTqVW9mXGcAuWHw"} // 发送认证消息: {"type":"auth","appUserId":"1964941649976532994","token":"eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2FwcGxldF9rZXkiOiJhMzkyMTdmZS1hZmRiLTQ1YTAtYjkwMy01MGViNjc4ZGJlNzAifQ.SaLnyIsAQ9lnSivaXPaO71gReSmx-R_tjrS3auKJqbXKe2SiLr7MZiNetdjmwvE7HSzjxs1yTqVW9mXGcAuWHw"} // 发送心跳消息: {"type":"ping","timestamp":1761294280878} // 发送业务消息: {"type":"business","content":"这是一条测试业务消息","timestamp":1761294280878} } /** * 发送无Token认证消息 */ private void sendAuthMessageWithoutToken() { JSONObject authMessage = new JSONObject(); authMessage.put("type", "auth"); authMessage.put("appUserId", TEST_USER_ID); String message = authMessage.toJSONString(); log.info("发送无Token认证消息: {}", message); } /** * 发送业务消息 */ private void sendBusinessMessage() { JSONObject businessMessage = new JSONObject(); businessMessage.put("type", "business"); businessMessage.put("content", "这是一条测试业务消息"); businessMessage.put("timestamp", System.currentTimeMillis()); String message = businessMessage.toJSONString(); log.info("发送业务消息: {}", message); } /** * 发送心跳消息 */ private void sendPingMessage() { JSONObject pingMessage = new JSONObject(); pingMessage.put("type", "ping"); pingMessage.put("timestamp", System.currentTimeMillis()); String message = pingMessage.toJSONString(); log.info("发送心跳消息: {}", message); } /** * 开始心跳 */ private void startHeartbeat() { // 每5秒发送一次心跳 new Thread(() -> { try { for (int i = 0; i < 6; i++) { Thread.sleep(5000); sendPingMessage(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); } /** * 处理服务器消息 */ private void handleMessage(String message) { try { JSONObject messageObj = JSON.parseObject(message); String messageType = messageObj.getString("type"); switch (messageType) { case "auth_success": log.info("认证成功: {}", messageObj.getString("message")); break; case "auth_failed": log.error("认证失败: {}", messageObj.getString("message")); break; case "pong": log.info("收到心跳响应"); break; case "message_response": log.info("收到业务消息响应"); break; case "auth_required": log.warn("需要重新认证: {}", messageObj.getString("message")); break; default: log.info("收到其他消息: {}", message); } } catch (Exception e) { log.error("解析消息失败: {}", e.getMessage()); } } /** * WebSocket客户端接口 */ public interface WebSocketClient { void connect() throws Exception; void send(String message); void close(); interface MessageHandler { void onOpen(); void onMessage(String message); void onClose(int code, String reason); void onError(Exception e); } } }