fix: fixed bugs for runtime application

This commit is contained in:
merlin
2025-12-16 18:28:26 +08:00
parent 44133d3667
commit 94d5d8cabe
13 changed files with 85 additions and 37 deletions

View File

@@ -21,6 +21,6 @@ public class WebsocketConfig implements WebSocketConfigurer {
@Override @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(handler, "/online").addInterceptors(interceptor); registry.addHandler(handler, "/ws/online").addInterceptors(interceptor).setAllowedOrigins("*");
} }
} }

View File

@@ -32,7 +32,8 @@ public class SecurityConfig {
"/health", "/health",
"/code/**", "/code/**",
"/v3/api-docs/**", "/v3/api-docs/**",
"/account/mail/verify/**" "/account/mail/verify/**",
"/ws/**"
).permitAll() ).permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
) )

View File

@@ -5,11 +5,13 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor; import org.springframework.web.socket.server.HandshakeInterceptor;
import xin.merlin.myplayerbackend.utils.JwtUtil; import xin.merlin.myplayerbackend.utils.JwtUtil;
import java.util.List;
import java.util.Map; import java.util.Map;
@Slf4j @Slf4j
@@ -23,21 +25,32 @@ public class WebsocketInterceptor implements HandshakeInterceptor {
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
try { try {
// 获取 token // 获取 token
String token = request.getHeaders().getFirst("Authorization"); List<String> protocols = request.getHeaders().get("Sec-WebSocket-Protocol");
if (token != null && token.startsWith("Bearer ")) { String token = null;
token = token.substring(7); if (protocols == null){
log.info("no token!");
return false;
}
String tokenHeader = protocols.get(0);
// System.out.println(tokenHeader);
response.getHeaders().add("Sec-WebSocket-Protocol",tokenHeader);
token = tokenHeader.replace("token-", "");
if (jwtUtil.isTokenExpired(token)){ if (jwtUtil.isTokenExpired(token)){
log.info("token expired"); log.info("token expired");
return false; return false;
} }
} else { Integer id = jwtUtil.getId(token);
return false; String account = jwtUtil.getAccount(token);
attributes.put("id", id);
attributes.put("account", account);
if (request instanceof ServletServerHttpRequest servletRequest) {
String userName = servletRequest.getServletRequest().getParameter("name");
if (userName != null) {
attributes.put("name", userName); // 将u_name存储到Attributes中
}
} }
Integer id = jwtUtil.getId(token);
attributes.put("userId", id);
return true; return true;
}catch (Exception e){ }catch (Exception e){
log.error(e.getMessage()); log.error(e.getMessage());
return false; return false;

View File

@@ -1,6 +1,7 @@
package xin.merlin.myplayerbackend.entity; package xin.merlin.myplayerbackend.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
@@ -10,7 +11,7 @@ import lombok.NoArgsConstructor;
@TableName("account") @TableName("account")
@NoArgsConstructor @NoArgsConstructor
public class Account { public class Account {
@TableId("id") @TableId(value = "id",type = IdType.AUTO)
private Integer id; private Integer id;
private String account; private String account;

View File

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime;
@Data @Data
@TableName("inviting") @TableName("inviting")
public class Inviting { public class Inviting {
@@ -16,4 +18,5 @@ public class Inviting {
// 0 表示未处理 1 表示同意 2 表示拒绝 // 0 表示未处理 1 表示同意 2 表示拒绝
private Integer status; private Integer status;
private Integer room; private Integer room;
private LocalDateTime time;
} }

View File

@@ -5,6 +5,8 @@ import lombok.NoArgsConstructor;
import xin.merlin.myplayerbackend.entity.Inviting; import xin.merlin.myplayerbackend.entity.Inviting;
import xin.merlin.myplayerbackend.entity.UserInfo; import xin.merlin.myplayerbackend.entity.UserInfo;
import java.time.LocalDateTime;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class InvitingDetails { public class InvitingDetails {
@@ -18,6 +20,7 @@ public class InvitingDetails {
// 0 表示未处理 1 表示已处理 // 0 表示未处理 1 表示已处理
private Integer status; private Integer status;
private Integer room; private Integer room;
private LocalDateTime time;
public InvitingDetails(Inviting inviting, UserInfo userInfo) { public InvitingDetails(Inviting inviting, UserInfo userInfo) {
this.i_id = inviting.getI_id(); this.i_id = inviting.getI_id();
@@ -27,5 +30,6 @@ public class InvitingDetails {
this.room = inviting.getRoom(); this.room = inviting.getRoom();
this.inviter_name = userInfo.getU_name(); this.inviter_name = userInfo.getU_name();
this.inviter_avatar = userInfo.getU_avatar(); this.inviter_avatar = userInfo.getU_avatar();
this.time = inviting.getTime();
} }
} }

View File

@@ -67,9 +67,9 @@ public class LoginService{
u.setId(account.getId()); u.setId(account.getId());
do{ do{
u.setU_id(RandomCode.generateID()); u.setU_id(RandomCode.generateID());
}while (userMapper.selectById(u.getU_id())!=null); }while (userMapper.selectOne(Wrappers.<UserInfo>lambdaQuery().eq(UserInfo::getU_id,u.getU_id()))!=null);
userMapper.insert(u); userMapper.insert(u);
u = userMapper.selectById(u.getU_id()); u = userMapper.selectById(u.getId());
codeService.getWaitingList().invalidate(code.getC_id()); codeService.getWaitingList().invalidate(code.getC_id());
return Response.success(ResultCode.SUCCESS,Map.of("token",jwtUtil.generateToken(account),"token_type","Bearer","userinfo",u)); return Response.success(ResultCode.SUCCESS,Map.of("token",jwtUtil.generateToken(account),"token_type","Bearer","userinfo",u));
} }

View File

@@ -16,6 +16,7 @@ import xin.merlin.myplayerbackend.mapper.InvitingMapper;
import xin.merlin.myplayerbackend.mapper.PlayroomsMapper; import xin.merlin.myplayerbackend.mapper.PlayroomsMapper;
import xin.merlin.myplayerbackend.mapper.UserMapper; import xin.merlin.myplayerbackend.mapper.UserMapper;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -48,10 +49,11 @@ public class InvitingServiceImpl extends ServiceImpl<InvitingMapper, Inviting> {
inviting.setInviter(inviter); inviting.setInviter(inviter);
inviting.setTarget(target); inviting.setTarget(target);
inviting.setStatus(0); inviting.setStatus(0);
inviting.setTime(LocalDateTime.now());
if (room != null){ if (room != null){
inviting.setRoom(room); inviting.setRoom(room);
} }
if (invitingMapper.selectCount(Wrappers.<Inviting>lambdaQuery().eq(Inviting::getInviter,inviter).eq(Inviting::getTarget,target).eq(Inviting::getStatus,0).eq(Inviting::getRoom,room)) > 0) return false; if (invitingMapper.selectCount(Wrappers.<Inviting>lambdaQuery().eq(Inviting::getInviter,inviter).eq(Inviting::getTarget,target).eq(Inviting::getStatus,0).isNull(Inviting::getRoom)) > 0) return false;
return invitingMapper.insert(inviting) == 1; return invitingMapper.insert(inviting) == 1;
} }
@@ -81,12 +83,15 @@ public class InvitingServiceImpl extends ServiceImpl<InvitingMapper, Inviting> {
public Boolean handleFriendInviting(Inviting inviting) { public Boolean handleFriendInviting(Inviting inviting) {
try { try {
if (inviting.getStatus().equals(0)) return false; if (inviting.getStatus().equals(0)) return false;
else if (inviting.getStatus().equals(1)){ else{
if(inviting.getStatus().equals(1)){
friendsMapper.insert(new Friends(inviting.getInviter(), inviting.getTarget(), null)); friendsMapper.insert(new Friends(inviting.getInviter(), inviting.getTarget(), null));
friendsMapper.insert(new Friends(inviting.getTarget(), inviting.getInviter(), null)); friendsMapper.insert(new Friends(inviting.getTarget(), inviting.getInviter(), null));
}
inviting.setTime(LocalDateTime.now());
invitingMapper.updateById(inviting);
return true; return true;
} }
else return true;
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
throw new RuntimeException(e); throw new RuntimeException(e);

View File

@@ -1,8 +1,5 @@
package xin.merlin.myplayerbackend.utils.websocket; package xin.merlin.myplayerbackend.utils.websocket;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -30,7 +27,14 @@ public class CustomWebSocketHandler extends TextWebSocketHandler {
@Override @Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception { public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Integer userId = (Integer) session.getAttributes().get("userId"); /*
TODO这里需要处理在数据库中未发送的离线消息
初步想法:
开多线程分页获取所有相关信息然后送入rabbitmq送入之后删除对应的message
但是需要处理的是用户一上线即下线的问题如何终止这个多线程任务以及送入rabbitmq的message可能又会回到数据库中并出现重复数据
*/
Integer userId = (Integer) session.getAttributes().get("id");
onlineStatusService.online(userId); onlineStatusService.online(userId);
@@ -64,7 +68,7 @@ public class CustomWebSocketHandler extends TextWebSocketHandler {
@Override @Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Integer userId = (Integer) session.getAttributes().get("userId"); Integer userId = (Integer) session.getAttributes().get("id");
onlineStatusService.offline(userId); onlineStatusService.offline(userId);

View File

@@ -22,17 +22,7 @@ public class WebSocketMessageConsumer {
public void onMessage(String json) { public void onMessage(String json) {
try { try {
JSONObject msg = JSON.parseObject(json); JSONObject msg = JSON.parseObject(json);
String to = msg.getString("to");
if (to == null || to.isEmpty()) {
// 这是广播 / 系统消息
sessionManager.broadcast(json);
} else {
// 单发消息
// sessionManager.sendToUser(Integer.valueOf(to), json);
commandDispatcher.dispatch(msg); commandDispatcher.dispatch(msg);
}
} catch (Exception e) { } catch (Exception e) {
log.info(e.getMessage()); log.info(e.getMessage());

View File

@@ -15,6 +15,7 @@ public class CommandDispatcher {
private final Typing typingCommand; private final Typing typingCommand;
private final Heartbeat heartbeatCommand; private final Heartbeat heartbeatCommand;
private final SystemNotify systemNotifyCommand; private final SystemNotify systemNotifyCommand;
private final PersonalNotify personalNotifyCommand;
public void dispatch(JSONObject msg) throws IOException { public void dispatch(JSONObject msg) throws IOException {
String cmd = msg.getString("cmd"); String cmd = msg.getString("cmd");
@@ -25,6 +26,7 @@ public class CommandDispatcher {
case "TYPING" -> typingCommand.handle(msg); case "TYPING" -> typingCommand.handle(msg);
case "HEARTBEAT" -> heartbeatCommand.handle(msg); case "HEARTBEAT" -> heartbeatCommand.handle(msg);
case "SYSTEM_NOTIFY" -> systemNotifyCommand.handle(msg); case "SYSTEM_NOTIFY" -> systemNotifyCommand.handle(msg);
case "PERSONAL_NOTIFY" -> personalNotifyCommand.handle(msg);
default -> { default -> {
System.err.println("Unknown command: " + cmd); System.err.println("Unknown command: " + cmd);

View File

@@ -16,6 +16,9 @@ public class Message implements BaseCommandHandler {
@Override @Override
public void handle(JSONObject msg) throws IOException { public void handle(JSONObject msg) throws IOException {
/*
TODO: 这里需要处理如果目标用户不在线,如何去完成消息的存储
*/
String to = msg.getString("to"); String to = msg.getString("to");
sessionManager.sendToUser(Integer.valueOf(to), msg.toJSONString()); sessionManager.sendToUser(Integer.valueOf(to), msg.toJSONString());
} }

View File

@@ -0,0 +1,22 @@
package xin.merlin.myplayerbackend.utils.websocket.command.impl;
import com.alibaba.fastjson2.JSONObject;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import xin.merlin.myplayerbackend.utils.websocket.WebSocketSessionManager;
import xin.merlin.myplayerbackend.utils.websocket.command.BaseCommandHandler;
import java.io.IOException;
@Component
@RequiredArgsConstructor
public class PersonalNotify implements BaseCommandHandler {
private final WebSocketSessionManager sessionManager;
@Override
public void handle(JSONObject msg) throws IOException {
String to = msg.getString("to");
sessionManager.sendToUser(Integer.valueOf(to), msg.toJSONString());
}
}