这块请求都会被重定向到登陆页面

This commit is contained in:
2025-07-29 17:14:16 +08:00
parent ecb5ec77d4
commit 66b7e8c757
5 changed files with 381 additions and 6 deletions

View File

@@ -1,14 +1,21 @@
package com.klp.web.controller.websocket; package com.klp.web.controller.websocket;
import cn.dev33.satoken.annotation.SaIgnore;
import com.klp.common.core.controller.BaseController; import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.R; import com.klp.common.core.domain.R;
import com.klp.framework.websocket.WebSocketUsers;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.websocket.Session;
import java.util.List;
import java.util.Map;
/** /**
* WebSocket测试控制器 * WebSocket测试控制器
* *
* @author klp * @author klp
*/ */
@SaIgnore
@RestController @RestController
@RequestMapping("/websocket/test") @RequestMapping("/websocket/test")
public class WebSocketTestController extends BaseController { public class WebSocketTestController extends BaseController {
@@ -16,17 +23,75 @@ public class WebSocketTestController extends BaseController {
/** /**
* 测试WebSocket端点是否可用 * 测试WebSocket端点是否可用
*/ */
@SaIgnore
@GetMapping("/status") @GetMapping("/status")
public R<String> getWebSocketStatus() { public R<String> getWebSocketStatus() {
System.out.println("=== WebSocket状态接口被调用 ===");
System.out.println("=== 当前线程: " + Thread.currentThread().getName() + " ===");
System.out.println("=== 请求路径: /websocket/test/status ===");
return R.ok("WebSocket端点可用连接地址: ws://localhost:8080/websocket/message"); return R.ok("WebSocket端点可用连接地址: ws://localhost:8080/websocket/message");
} }
/** /**
* 获取当前连接数 * 获取当前连接数
*/ */
@SaIgnore
@GetMapping("/connections") @GetMapping("/connections")
public R<Integer> getConnectionCount() { public R<Integer> getConnectionCount() {
// 这里可以调用WebSocketUsers.getUsers().size()来获取实际连接数 try {
return R.ok(0); int count = WebSocketUsers.getUsers().size();
return R.ok(count);
} catch (Exception e) {
return R.ok(0);
}
} }
}
/**
* 发送广播消息
*/
@SaIgnore
@PostMapping("/broadcast")
public R<String> sendBroadcast(@RequestParam String message) {
try {
WebSocketUsers.sendMessageToUsersByText("系统广播: " + message);
return R.ok("广播消息发送成功");
} catch (Exception e) {
return R.fail("广播消息发送失败: " + e.getMessage());
}
}
/**
* 发送消息给指定用户
*/
@SaIgnore
@PostMapping("/sendToUser")
public R<String> sendToUser(@RequestParam String sessionId, @RequestParam String message) {
try {
Map<String, Session> users = WebSocketUsers.getUsers();
Session session = users.get(sessionId);
if (session != null) {
WebSocketUsers.sendMessageToUserByText(session, "私信: " + message);
return R.ok("消息发送成功");
} else {
return R.fail("用户不在线或会话ID无效");
}
} catch (Exception e) {
return R.fail("消息发送失败: " + e.getMessage());
}
}
/**
* 获取所有在线用户会话ID
*/
@SaIgnore
@GetMapping("/users")
public R<List<String>> getOnlineUsers() {
try {
Map<String, Session> users = WebSocketUsers.getUsers();
List<String> sessionIds = new java.util.ArrayList<>(users.keySet());
return R.ok(sessionIds);
} catch (Exception e) {
return R.ok(new java.util.ArrayList<>());
}
}
}

View File

@@ -143,6 +143,11 @@ security:
# WebSocket路径 # WebSocket路径
- /websocket/** - /websocket/**
- /wms/websocket/** - /wms/websocket/**
# WebSocket测试接口
- /websocket/test/**
- /websocket/direct/**
# 测试接口
- /test/**
# MyBatisPlus配置 # MyBatisPlus配置

View File

@@ -7,6 +7,7 @@ import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpInterface; import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import java.util.Arrays;
import com.klp.common.utils.spring.SpringUtils; import com.klp.common.utils.spring.SpringUtils;
import com.klp.framework.config.properties.SecurityProperties; import com.klp.framework.config.properties.SecurityProperties;
import com.klp.framework.handler.AllUrlHandler; import com.klp.framework.handler.AllUrlHandler;
@@ -58,6 +59,9 @@ public class SaTokenConfig implements WebMvcConfigurer {
})).addPathPatterns("/**") })).addPathPatterns("/**")
// 排除不需要拦截的路径 // 排除不需要拦截的路径
.excludePathPatterns(securityProperties.getExcludes()); .excludePathPatterns(securityProperties.getExcludes());
// 添加调试日志
log.info("Sa-Token拦截器配置完成排除路径: {}", Arrays.toString(securityProperties.getExcludes()));
} }
@Bean @Bean

View File

@@ -116,7 +116,7 @@ public class WebSocketUsers
/** /**
* 发送文本消息 * 发送文本消息
* *
* @param userName 自己的用户名 * @param session 自己的用户名
* @param message 消息内容 * @param message 消息内容
*/ */
public static void sendMessageToUserByText(Session session, String message) public static void sendMessageToUserByText(Session session, String message)

View File

@@ -97,6 +97,34 @@
.back-btn { .back-btn {
margin-bottom: 20px; margin-bottom: 20px;
} }
.btn-warning {
background-color: #ffc107;
color: #212529;
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-success {
background-color: #28a745;
color: white;
}
select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
select:disabled {
background-color: #f8f9fa;
cursor: not-allowed;
}
</style> </style>
</head> </head>
@@ -118,6 +146,34 @@
<button id="btn_join" class="btn btn-primary">连接</button> <button id="btn_join" class="btn btn-primary">连接</button>
<button id="btn_exit" class="btn btn-danger" disabled>断开</button> <button id="btn_exit" class="btn btn-danger" disabled>断开</button>
<button id="btn_test_server" class="btn btn-info">测试服务器</button> <button id="btn_test_server" class="btn btn-info">测试服务器</button>
<button id="btn_test_direct" class="btn btn-warning">直接测试接口</button>
</div>
<div class="control-panel">
<div class="input-group">
<label for="broadcast_message">广播消息:</label>
<input type="text" id="broadcast_message" placeholder="输入要广播的消息">
</div>
<div class="button-group">
<button id="btn_broadcast" class="btn btn-warning" disabled>发送广播</button>
</div>
</div>
<div class="control-panel">
<div class="input-group">
<label for="user_session">用户会话ID:</label>
<select id="user_session" disabled>
<option value="">请先获取在线用户</option>
</select>
</div>
<div class="input-group">
<label for="private_message">私信内容:</label>
<input type="text" id="private_message" placeholder="输入私信内容">
</div>
<div class="button-group">
<button id="btn_get_users" class="btn btn-secondary">获取在线用户</button>
<button id="btn_send_private" class="btn btn-success" disabled>发送私信</button>
</div>
</div> </div>
<div id="status" class="status disconnected"> <div id="status" class="status disconnected">
@@ -152,6 +208,9 @@
var joinBtn = document.getElementById('btn_join'); var joinBtn = document.getElementById('btn_join');
var exitBtn = document.getElementById('btn_exit'); var exitBtn = document.getElementById('btn_exit');
var sendBtn = document.getElementById('btn_send'); var sendBtn = document.getElementById('btn_send');
var broadcastBtn = document.getElementById('btn_broadcast');
var getUsersBtn = document.getElementById('btn_get_users');
var sendPrivateBtn = document.getElementById('btn_send_private');
if (connected) { if (connected) {
statusDiv.textContent = '已连接'; statusDiv.textContent = '已连接';
@@ -159,12 +218,18 @@
joinBtn.disabled = true; joinBtn.disabled = true;
exitBtn.disabled = false; exitBtn.disabled = false;
sendBtn.disabled = false; sendBtn.disabled = false;
broadcastBtn.disabled = false;
getUsersBtn.disabled = false;
sendPrivateBtn.disabled = false;
} else { } else {
statusDiv.textContent = '未连接'; statusDiv.textContent = '未连接';
statusDiv.className = 'status disconnected'; statusDiv.className = 'status disconnected';
joinBtn.disabled = false; joinBtn.disabled = false;
exitBtn.disabled = true; exitBtn.disabled = true;
sendBtn.disabled = true; sendBtn.disabled = true;
broadcastBtn.disabled = true;
getUsersBtn.disabled = true;
sendPrivateBtn.disabled = true;
} }
} }
@@ -230,10 +295,21 @@
addLog('正在测试服务器状态...'); addLog('正在测试服务器状态...');
fetch('/websocket/test/status') fetch('/websocket/test/status')
.then(response => { .then(response => {
addLog('服务器响应状态: ' + response.status + ' ' + response.statusText);
if (response.ok) { if (response.ok) {
return response.json(); return response.text().then(text => {
try {
return JSON.parse(text);
} catch (e) {
addLog('响应内容不是JSON格式: ' + text.substring(0, 200));
throw new Error('响应格式错误');
}
});
} else { } else {
throw new Error('服务器响应错误: ' + response.status); return response.text().then(text => {
addLog('错误响应内容: ' + text.substring(0, 200));
throw new Error('服务器响应错误: ' + response.status);
});
} }
}) })
.then(data => { .then(data => {
@@ -244,6 +320,231 @@
}); });
}); });
// 直接测试接口
$('#btn_test_direct').click(function() {
addLog('=== 直接测试接口开始 ===');
// 测试1: 直接访问接口
addLog('测试1: 直接访问 /websocket/test/status');
fetch('/websocket/test/status', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => {
addLog('响应状态: ' + response.status + ' ' + response.statusText);
addLog('响应头: ' + JSON.stringify(Object.fromEntries(response.headers.entries())));
return response.text();
}).then(text => {
addLog('响应内容: ' + text.substring(0, 500));
if (text.includes('<!DOCTYPE html>')) {
addLog('❌ 返回了HTML页面说明被重定向到登录页面');
} else {
addLog('✅ 返回了非HTML内容');
}
}).catch(error => {
addLog('请求失败: ' + error.message);
});
// 测试2: 测试简单控制器
setTimeout(() => {
addLog('测试2: 测试 /test/hello简单控制器');
fetch('/test/hello', {
method: 'GET'
}).then(response => {
addLog('简单控制器响应状态: ' + response.status + ' ' + response.statusText);
return response.text();
}).then(text => {
addLog('简单控制器响应内容: ' + text.substring(0, 200));
if (text.includes('<!DOCTYPE html>')) {
addLog('❌ 简单控制器也返回了HTML页面');
} else {
addLog('✅ 简单控制器返回了非HTML内容');
}
}).catch(error => {
addLog('简单控制器请求失败: ' + error.message);
});
}, 1000);
// 测试3: 测试actuator接口应该工作
setTimeout(() => {
addLog('测试3: 测试 /actuator/health应该工作');
fetch('/actuator/health', {
method: 'GET'
}).then(response => {
addLog('Actuator响应状态: ' + response.status + ' ' + response.statusText);
return response.text();
}).then(text => {
addLog('Actuator响应内容: ' + text.substring(0, 200));
}).catch(error => {
addLog('Actuator请求失败: ' + error.message);
});
}, 2000);
addLog('=== 直接测试接口结束 ===');
});
// 测试连接数
$('#btn_test_data').click(function() {
addLog('正在获取连接数...');
fetch('/websocket/test/connections', {
method: 'GET'
}).then(response => {
addLog('连接数响应状态: ' + response.status + ' ' + response.statusText);
if (response.ok) {
return response.text().then(text => {
try {
return JSON.parse(text);
} catch (e) {
addLog('连接数响应内容不是JSON格式: ' + text.substring(0, 200));
throw new Error('响应格式错误');
}
});
} else {
return response.text().then(text => {
addLog('连接数错误响应内容: ' + text.substring(0, 200));
throw new Error('获取连接数失败: ' + response.status);
});
}
}).then(data => {
addLog('当前连接数: ' + data.data);
}).catch(error => {
addLog('获取连接数失败: ' + error.message);
});
});
// 发送广播消息
$('#btn_broadcast').click(function() {
var message = $('#broadcast_message').val();
if (!message.trim()) {
addLog('请输入广播消息内容');
return;
}
addLog('正在发送广播消息: ' + message);
var formData = new FormData();
formData.append('message', message);
fetch('/websocket/test/broadcast', {
method: 'POST',
body: formData
}).then(response => {
addLog('广播响应状态: ' + response.status + ' ' + response.statusText);
if (response.ok) {
return response.text().then(text => {
try {
return JSON.parse(text);
} catch (e) {
addLog('广播响应内容不是JSON格式: ' + text.substring(0, 200));
throw new Error('响应格式错误');
}
});
} else {
return response.text().then(text => {
addLog('广播错误响应内容: ' + text.substring(0, 200));
throw new Error('广播发送失败: ' + response.status);
});
}
}).then(data => {
addLog('广播结果: ' + data.msg);
$('#broadcast_message').val('');
}).catch(error => {
addLog('广播发送失败: ' + error.message);
});
});
// 获取在线用户
$('#btn_get_users').click(function() {
addLog('正在获取在线用户...');
fetch('/websocket/test/users', {
method: 'GET'
}).then(response => {
addLog('用户列表响应状态: ' + response.status + ' ' + response.statusText);
if (response.ok) {
return response.text().then(text => {
try {
return JSON.parse(text);
} catch (e) {
addLog('用户列表响应内容不是JSON格式: ' + text.substring(0, 200));
throw new Error('响应格式错误');
}
});
} else {
return response.text().then(text => {
addLog('用户列表错误响应内容: ' + text.substring(0, 200));
throw new Error('获取用户列表失败: ' + response.status);
});
}
}).then(data => {
addLog('在线用户数量: ' + data.data.length);
updateUserSelect(data.data);
}).catch(error => {
addLog('获取用户列表失败: ' + error.message);
});
});
// 发送私信
$('#btn_send_private').click(function() {
var sessionId = $('#user_session').val();
var message = $('#private_message').val();
if (!sessionId) {
addLog('请选择要发送的用户');
return;
}
if (!message.trim()) {
addLog('请输入私信内容');
return;
}
addLog('正在发送私信给用户 ' + sessionId + ': ' + message);
var formData = new FormData();
formData.append('sessionId', sessionId);
formData.append('message', message);
fetch('/websocket/test/sendToUser', {
method: 'POST',
body: formData
}).then(response => {
addLog('私信响应状态: ' + response.status + ' ' + response.statusText);
if (response.ok) {
return response.text().then(text => {
try {
return JSON.parse(text);
} catch (e) {
addLog('私信响应内容不是JSON格式: ' + text.substring(0, 200));
throw new Error('响应格式错误');
}
});
} else {
return response.text().then(text => {
addLog('私信错误响应内容: ' + text.substring(0, 200));
throw new Error('私信发送失败: ' + response.status);
});
}
}).then(data => {
addLog('私信结果: ' + data.msg);
$('#private_message').val('');
}).catch(error => {
addLog('私信发送失败: ' + error.message);
});
});
// 更新用户选择下拉框
function updateUserSelect(users) {
var select = $('#user_session');
select.empty();
select.append('<option value="">请选择用户</option>');
users.forEach(function(user) {
select.append('<option value="' + user + '">' + user + '</option>');
});
select.prop('disabled', false);
addLog('用户列表已更新');
}
// 回车发送消息 // 回车发送消息
$('#message').keypress(function(e) { $('#message').keypress(function(e) {
if (e.which == 13 && !e.shiftKey) { if (e.which == 13 && !e.shiftKey) {