Commit beb3de1a authored by daniel's avatar daniel

fix(websocket): 两种方式的测试+联调

parent bb076059
......@@ -2,6 +2,7 @@ package com.dlbridge.jadp.config.web;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
......@@ -12,8 +13,15 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 启用简单的内存消息代理,指定消息代理目的地前缀
config.enableSimpleBroker("/topic", "/queue");
// 创建一个调度器,用于心跳定时任务
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(1);
taskScheduler.setThreadNamePrefix("wss-heartbeat-thread-");
taskScheduler.initialize();
// 启用简单消息代理,并配置心跳
config.enableSimpleBroker("/topic", "/queue")
.setHeartbeatValue(new long[]{10000, 10000}) // 服务端和客户端心跳间隔(毫秒)
.setTaskScheduler(taskScheduler);
// 设置应用程序目的地前缀
config.setApplicationDestinationPrefixes("/app");
// 设置用户目的地前缀(点对点消息)
......@@ -24,7 +32,8 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注册 STOMP 端点,指定使用 SockJS
registry.addEndpoint("/ws").setAllowedOrigins("*") // 允许所有来源,生产环境应指定具体域名
.withSockJS();
.withSockJS()
.setHeartbeatTime(10000);
// 同时支持原生 WebSocket
registry.addEndpoint("/ws")
......
......@@ -28,10 +28,11 @@ public class BusController {
/**
* 查询个人购票列表
*
* @return 个人购票列表
*/
@ResponseBody
@ApiOperation(value = "获取个人购票列表", notes = "获取个人购票列表")
@ApiOperation(value = "获取个人购票列表", notes = "获取个人购票列表")
@RequestMapping(value = "/mine/tickets", method = RequestMethod.POST)
public Result<List<BusTicketVerification>> getPersonalTickets(@RequestBody BusParam param) {
List<BusTicketVerification> tickets = busService.selectTicketByIdNumber(param.getCmptId(), param.getIdNumber());
......@@ -40,12 +41,13 @@ public class BusController {
/**
* 查询车票详情
*
* @param param 查询参数
* @return 车票详情
*/
@ResponseBody
@RequestMapping(value = "/ticket/detail", method = RequestMethod.POST)
@ApiOperation(value = "获取车票详情", notes = "获取车票详情")
@ApiOperation(value = "获取车票详情", notes = "获取车票详情")
public Result<BusTicketVerification> getTicketDetail(@RequestBody BusParam param) {
BusTicketVerification ticket = busService.getTicketDetail(param.getCmptId(), param.getTicketNo());
return Result.success(ticket);
......@@ -53,7 +55,8 @@ public class BusController {
/**
* 生成车票二维码
* @param cmptId 赛事ID
*
* @param cmptId 赛事ID
* @param ticketNo 车票号
* @return 乘车二维码图片
*/
......@@ -69,10 +72,11 @@ public class BusController {
/**
* 车票核销接口
*
* @return 核销结果
*/
@ResponseBody
@ApiOperation(value = "核销车票", notes = "核销车票")
@ApiOperation(value = "核销车票", notes = "核销车票")
@RequestMapping(value = "/ticket/verify", method = RequestMethod.POST)
public Result<?> verifyTicket(@RequestBody BusParam param) {
return busService.verifyTicket(param);
......@@ -80,10 +84,11 @@ public class BusController {
/**
* 查询赛事班车列表接口
*
* @return 班车列表
*/
@ResponseBody
@ApiOperation(value = "获取赛事班车列表", notes = "获取赛事班车列表")
@ApiOperation(value = "获取赛事班车列表", notes = "获取赛事班车列表")
@RequestMapping(value = "/schedules", method = RequestMethod.POST)
public Result<?> selectSchedulesByCmptId(@RequestBody BusParam param) {
List<BusSchedule> schedules = busService.selectSchedulesByCmptId(param.getCmptId());
......@@ -93,10 +98,11 @@ public class BusController {
/**
* 查询班次途经站点列表
*
* @return 班次途经站点列表
*/
@ResponseBody
@ApiOperation(value = "获取班次途经站点列表", notes = "获取班次途经站点列表")
@ApiOperation(value = "获取班次途经站点列表", notes = "获取班次途经站点列表")
@RequestMapping(value = "/schedule-stations", method = RequestMethod.POST)
public Result<?> selectStationsByScheduleId(@RequestBody BusParam param) {
List<BusStation> stations = busService.selectStationsByScheduleId(param.getScheduleId());
......@@ -105,10 +111,11 @@ public class BusController {
/**
* 查询赛事班车站点列表
*
* @return 班车站点列表
*/
@ResponseBody
@ApiOperation(value = "获取赛事班车站点列表", notes = "获取赛事班车站点列表")
@ApiOperation(value = "获取赛事班车站点列表", notes = "获取赛事班车站点列表")
@RequestMapping(value = "/cmpt-stations", method = RequestMethod.POST)
public Result<?> selectStationsByCmptId(@RequestBody BusParam param) {
List<BusStation> stations = busService.selectStationsByCmptId(param.getCmptId());
......@@ -117,10 +124,11 @@ public class BusController {
/**
* 查询核销记录接口
*
* @return 核销记录列表
*/
@ResponseBody
@ApiOperation(value = "获取核销记录", notes = "获取核销记录")
@ApiOperation(value = "获取核销记录", notes = "获取核销记录")
@RequestMapping(value = "/verification-record", method = RequestMethod.POST)
public Result<?> selectVerificationRecord(@RequestBody BusParam param) {
List<BusVerificationRecord> records = busService.selectVerificationRecord(param.getCmptId(), param.getVerifierId(), param.getTicketNo());
......@@ -129,11 +137,12 @@ public class BusController {
/**
* 赛事核销统计
*
* @param cmptId 赛事ID
* @return 核销统计列表
*/
@ResponseBody
@ApiOperation(value = "获取赛事核销统计", notes = "获取赛事核销统计")
@ApiOperation(value = "获取赛事核销统计", notes = "获取赛事核销统计")
@RequestMapping(value = "/verify-statistics/{cmptId}", method = RequestMethod.GET)
public Result<?> busVerifyStatistics(@PathVariable("cmptId") Integer cmptId) {
List<BusVerifyStatistics> statistics = busService.busVerifyStatistics(cmptId);
......@@ -142,6 +151,7 @@ public class BusController {
/**
* 查询班车核销记录分页列表接口
*
* @param queryDTO 查询参数
* @return 班车核销记录分页列表
*/
......
......@@ -3,6 +3,7 @@ package com.dlbridge.jadp.websocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.*;
......@@ -31,13 +32,15 @@ public class WebSocketSessionService {
/**
* 注册用户会话
* @param userId 用户ID(赛事ID+证件号,例:29643-HK002949527)
* @param ticketNo 票号
*
* @param userId 用户ID(赛事ID+证件号,例:29643-HK002949527)
* @param ticketNo 票号
* @param sessionId 会话ID
*/
public void registerUserSession(String userId, String ticketNo, String sessionId) {
// 更新用户-票号映射
userTicketsMap.computeIfAbsent(userId, k -> ConcurrentHashMap.newKeySet()).add(ticketNo);
userTicketsMap.computeIfAbsent(userId, k -> ConcurrentHashMap.newKeySet())
.add(ticketNo);
// 更新票号-用户映射
ticketUserMap.put(ticketNo, userId);
......@@ -46,15 +49,16 @@ public class WebSocketSessionService {
sessionUserMap.put(sessionId, userId);
// 更新会话-票号映射
sessionTicketsMap.computeIfAbsent(sessionId, k -> ConcurrentHashMap.newKeySet()).add(ticketNo);
sessionTicketsMap.computeIfAbsent(sessionId, k -> ConcurrentHashMap.newKeySet())
.add(ticketNo);
log.info("用户会话注册成功 - 用户: {}, 票号: {}, 会话ID: {}", userId, ticketNo, sessionId);
log.debug("当前会话状态 - 用户数: {}, 票号数: {}, 会话数: {}",
userTicketsMap.size(), ticketUserMap.size(), sessionUserMap.size());
log.debug("当前会话状态 - 用户数: {}, 票号数: {}, 会话数: {}", userTicketsMap.size(), ticketUserMap.size(), sessionUserMap.size());
}
/**
* 移除用户会话
*
* @param sessionId 会话ID
*/
public void removeUserSession(String sessionId) {
......@@ -85,8 +89,9 @@ public class WebSocketSessionService {
/**
* 移除特定票号的会话
*
* @param sessionId 会话ID
* @param ticketNo 票号
* @param ticketNo 票号
*/
public void removeTicketSession(String sessionId, String ticketNo) {
// 从会话-票号映射中移除
......@@ -156,7 +161,7 @@ public class WebSocketSessionService {
log.info("核销成功通知已发送 - 用户: {}, 票号: {}, 消息: {}", userId, ticketNo, message);
// 核销成功后,移除该票号的会话映射
removeTicketMappings(ticketNo);
// removeTicketMappings(ticketNo);
} else {
log.warn("未找到对应的用户会话,无法发送核销通知 - 票号: {}", ticketNo);
}
......@@ -201,7 +206,8 @@ public class WebSocketSessionService {
}
// 从所有会话的票号集合中移除
sessionTicketsMap.values().forEach(tickets -> tickets.remove(ticketNo));
sessionTicketsMap.values()
.forEach(tickets -> tickets.remove(ticketNo));
log.info("票号映射关系已移除 - 票号: {}", ticketNo);
}
......@@ -218,7 +224,8 @@ public class WebSocketSessionService {
stats.put("activeSessions", sessionTicketsMap.size());
// 计算平均每个用户的票号数
double avgTicketsPerUser = userTicketsMap.values().stream()
double avgTicketsPerUser = userTicketsMap.values()
.stream()
.mapToInt(Set::size)
.average()
.orElse(0.0);
......
package com.dlbridge.jadp.websocket;
import com.dlbridge.jadp.common.web.Result;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.web.bind.annotation.*;
......@@ -18,16 +19,31 @@ public class WebSocketTestController {
/**
* 测试接口:向指定用户发送票号核销消息
*/
@PostMapping("/sendTicket")
public String sendTicketMessage(@RequestBody Map<String, String> body) {
@PostMapping("/sendToUser")
public Result<String> sendToUser(@RequestBody Map<String, String> body) {
String userId = body.get("userId");
String ticketNo = body.get("ticketNo");
if (userId == null || ticketNo == null) return "缺少 userId 或 ticketNo";
if (userId == null || ticketNo == null) return Result.fail("缺少 userId 或 ticketNo");
WebSocketMessage response = WebSocketMessage.info(ticketNo,
"这是一个测试消息,票号:" + ticketNo);
sessionService.sendToUser(userId, response);
// sessionService.sendVerificationSuccess(ticketNo,message);
return Result.success();
}
/**
* 测试接口:向指定用户发送票号核销消息
*/
@PostMapping("/sendToVerify")
public Result<String> sendToVerify(@RequestBody Map<String, String> body) {
String message = body.get("message");
String ticketNo = body.get("ticketNo");
if (message == null || ticketNo == null) return Result.fail("缺少 message 或 ticketNo");
// WebSocketMessage response = WebSocketMessage.info(ticketNo,
// "这是一个测试消息,票号:" + ticketNo);
// sessionService.sendToUser(userId, response);
sessionService.sendVerificationSuccess(ticketNo,message);
return "消息已发送到用户 " + userId;
return Result.success();
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment