当前位置: 首页 > news >正文

怎么用wordpress做网站seo外包优化

怎么用wordpress做网站,seo外包优化,网站设计报告总结,北京网站引入 技术细节 实现过程 WebSocket 后端 1、实体类 2、异常处理类 3、游戏状态枚举类 4、ws主类 5、配置类及工具类 引入 引入与技术选型#xff1a; 在实时互动应用中#xff0c;实现流畅的多人协同对战功能是一大挑战。WebSocket技术#xff0c;以其全双工通信… 引入 技术细节 实现过程 WebSocket 后端 1、实体类 2、异常处理类 3、游戏状态枚举类 4、ws主类 5、配置类及工具类 引入 引入与技术选型 在实时互动应用中实现流畅的多人协同对战功能是一大挑战。WebSocket技术以其全双工通信能力提供了解决方案。不同于传统HTTP请求的短连接WebSocket建立持久连接极大减少了通信延迟为实时数据传输提供了理想的环境极大减少了传统HTTP轮询的延迟为实时游戏提供了必要的技术基础。 架构设计 采用前后端分离将WebSocket服务独立部署。前端使用JavaScript建立与WebSocket服务器的连接实现即时消息交换后端则负责逻辑处理包括玩家匹配、状态同步等使用Java语言借助Spring框架的强大支持构建了稳定的WebSocket服务。 技术细节 状态同步在对战中通过WebSocket实时同步玩家的操作和游戏状态每个动作都通过服务器广播给所有参与者确保了游戏进程的同步性和准确性。 异常处理与稳定性 对于WebSocket连接。一旦检测到游戏中的某一方异常断开系统会自动结算对局。 用户状态设置 用户的状态可粗略分为匹配中对局中等不同的状态 用户匹配机制 项目中的匹配系统采用动态队列遵循先来后到并可以根据用户的段位等信息进行分开匹配一定程度上提升用户体验。 并发错误避免 在项目中每一次对局的双方用户的状态信息都将保存在一个hashmap当中实现一个房间的机制标记用户的状态为游戏中防止第三用户加入对局引发未知错误。 实现过程 整个对战大致可以分为三个部分对战前对战中对战后。 对战前 匹配对手匹配成功后服务器获取双方的个人信息以及单次对局中的题目列表发送到双方的客户端中。 对战中 双方用户答题提交答案后。客户端将答题信息发送到服务器中服务器将其广播到对方客户端中。刷新双方分数信息。之后的每一次答题均重复其过程。 对战后 答题完毕刷新用户为结算状态。服务器根据双方得分情况判断胜负广播到双方客户端中。 此篇先介绍后端相关 WebSocket 后端 位于ws包中 1、实体类 1). 通信信息类 ChatMessageT Data public class ChatMessageT {/*** 消息类型*/private MessageTypeEnum type;/*** 消息发送者*/private String sender;/*** 消息接收者*/private SetString receivers;private T data; }MessageTypeEnum : 指此通信信息的类型 即pk中每一个阶段的不同信息类型 eg匹配中 详见下文 sender : 指此通信信息的发出方 这些响应信息是由谁来发出的 Set receivers : 指此通信信息的接收方 这些信息是由谁来接受 这个谁可以是单个人也可以是一群人 T data : 指此信息中包含的实际数据 由 MessageTypeEnum 来确认信息的类型data 表示信息的数据 2). 消息类型枚举类 MessageTypeEnum /*** 消息类型*/ public enum MessageTypeEnum {/*** 匹配对手*/MATCH_USER,/*** 游戏开始*/PLAY_GAME,/*** 游戏结束*/GAME_OVER, }此枚举类的三个信息分别代表在游戏的不同阶段中三个不同的状态不同的状态下发出不同的信息 3). 回答情况 AnswerSituation Data AllArgsConstructor NoArgsConstructor Component public class AnswerSituation {private ArrayListString selfAnswerSituations; }此实体类代表着用户pk答题的情况 每一个用户 在每一局游戏中 每一个用户 都会有一个自己的 AnswerSituation 4). 单局游戏回答情况 RoomAnswerSituation Data AllArgsConstructor NoArgsConstructor public class RoomAnswerSituation {private String userId;private String receiver;private AnswerSituation selfAnswerSituations;private AnswerSituation opponentAnswerSituations; }其中一种响应信息的类型 (GAME_OVER) 所对应的T data数据包含每一局游戏中双方的回答情况以及对方和自己的id标识便于前端判断 5). 用户的信息 UserMatchInfo Data public class UserMatchInfo {private String userId;private Integer score; }包含用户的id及分数 在响应信息类型为 (TO_PLAY) 时 传输对方用户以及自己的分数信息 在响应信息类型为 (MATCH_USER) 时 初始化双方的分数总分及id信息 6). 游戏对局信息 GameMatchInfo Data public class GameMatchInfo {// TODO UserMatchInfo 后期按需扩充dan等属性private UserMatchInfo selfInfo;private UserMatchInfo opponentInfo;private ListQuestion questions; //    用户名private String selfUsername;private String opponentUsername; //    头像private String selfPicAvatar;private String opponentPicAvatar; }在匹配到对手之后 发送的chatMessage中的 T data 数据类型 包含在这一轮游戏中 自己以及对方的数据信息 此处包含双方 id 用户名 头像 问题 以及初始化后的用户总分信息0 可进一步优化封装为 双方游戏信息类 问题信息类 7). 分数选项的反馈信息 ScoreSelectedInfo Data AllArgsConstructor NoArgsConstructor public class ScoreSelectedInfo {private UserMatchInfo userMatchInfo;private String userSelectedAnswer; }包含用户信息 UserMatchInfo 及 userSelectedAnswer 顾名思义 其为用户每一题所选择的答案 此程序中记录的是问题的答案 数组中的具体值 可优化改变换成记录数组对应索引etc 2、异常处理类 1). 错误码定义的统一接口 public interface IServerError {/*** 返回错误码** return 错误码*/Integer getErrorCode();/*** 返回错误详细信息** return 错误详细信息*/String getErrorDesc(); }2). 运行时错误 public enum GameServerError implements IServerError {/*** 枚举型错误码*/WEBSOCKET_ADD_USER_FAILED(4018, 用户进入匹配模式失败),MESSAGE_TYPE_ERROR(4019, websocket 消息类型错误),;private final Integer errorCode;private final String errorDesc;GameServerError(Integer errorCode, String errorDesc) {this.errorCode errorCode;this.errorDesc errorDesc;}Overridepublic Integer getErrorCode() {return errorCode;}Overridepublic String getErrorDesc() {return errorDesc;} }枚举错误类型及错误码 3). 运行时异常 public class GameServerException extends RuntimeException {private Integer code;private String message;public GameServerException(GameServerError error) {super(error.getErrorDesc());this.code error.getErrorCode();}public Integer getCode() {return code;}public void setCode(Integer code) {this.code code;} }统一规范抛出的异常及其错误类型 3、游戏状态枚举类 public enum EnumRedisKey {/*** userOnline 在线状态*/USER_STATUS,/*** userOnline 匹配信息*/USER_MATCH_INFO,/*** 房间*/ROOM;public String getKey() {return this.name();} }使用枚举类规定游戏中玩家的状态 并且使用redis进行存储 4、ws主类 此部分代码分为多板块 此类完整代码见附 1). 注入的相关类 private Session session;private String userId;static MatchCacheUtil matchCacheUtil; // 修改 查看用户的在线状态 客户端存储状态工具类static Lock lock new ReentrantLock(); static Condition matchCond lock.newCondition(); // 锁 防止并发异常情况static QuestionService questionService; // 题目业务类 用于在题库中随机获取题目static CompetitionService competitionService; // 比赛业务类 用于获取用户段位信息等 pk相关的功能信息static UserService userService; // 用户业务类 用于获取用户个人信息static AnswerSituationUtil answerSituationUtil; // 存储用户单轮答案信息 工具类Autowired public void setQuestionService(QuestionService questionService) {ChatWebsocket.questionService questionService; }Autowired public void setQuestionService(CompetitionService competitionService) {ChatWebsocket.competitionService competitionService; }Autowired public void setQuestionService(UserService userService) {ChatWebsocket.userService userService; }Autowired public void setMatchCacheUtil(MatchCacheUtil matchCacheUtil) {ChatWebsocket.matchCacheUtil matchCacheUtil; }Autowired public void setAnswerSituationUtil(AnswerSituationUtil answerSituationUtil) {ChatWebsocket.answerSituationUtil answerSituationUtil; }// 类单例模式注入相关业务工具类详细工具类见下一部分 2). 主要架构 OnOpen public void onOpen(PathParam(userId) String userId, Session session) {System.out.println(session);log.info(ChatWebsocket open 有新连接加入 userId: {}, userId);this.userId userId;this.session session;matchCacheUtil.addClient(userId, this);log.info(ChatWebsocket open 连接建立完成 userId: {}, userId); }onOpen: 建立ws连接时调用 使用工具类存储当前客户端的 id和webSocket对象 入redis中 便于后期调用 OnError public void onError(Session session, Throwable error) {log.error(ChatWebsocket onError 发生了错误 userId: {}, errorMessage: {}, userId, error.getMessage());matchCacheUtil.removeClinet(userId);matchCacheUtil.removeUserOnlineStatus(userId);matchCacheUtil.removeUserFromRoom(userId);matchCacheUtil.removeUserMatchInfo(userId);log.info(ChatWebsocket onError 连接断开完成 userId: {}, userId); }OnClose public void onClose() {log.info(ChatWebsocket onClose 连接断开 userId: {}, userId);matchCacheUtil.removeClinet(userId);matchCacheUtil.removeUserOnlineStatus(userId);matchCacheUtil.removeUserFromRoom(userId);matchCacheUtil.removeUserMatchInfo(userId);log.info(ChatWebsocket onClose 连接断开完成 userId: {}, userId); }OnError: 遇到异常时退出并调用 将用户信息经过工具类 从redis中移除 OnClose: 同理 断开连接时调用 正常使用时机为 用户pk结束 OnMessage public void onMessage(String message, Session session) {log.info(ChatWebsocket onMessage userId: {}, 来自客户端的消息 message: {}, userId, message);JSONObject jsonObject JSON.parseObject(message);MessageTypeEnum type  jsonObject.getObject(type, MessageTypeEnum.class);log.info(ChatWebsocket onMessage userId: {}, 来自客户端的消息类型 type: {}, userId, type);if (type  MessageTypeEnum.MATCH_USER) {matchUser(jsonObject);} elseif (type  MessageTypeEnum.PLAY_GAME) {toPlay(jsonObject);} elseif (type  MessageTypeEnum.GAME_OVER) {gameover(jsonObject);} else {throw new GameServerException(GameServerError.WEBSOCKET_ADD_USER_FAILED);}log.info(ChatWebsocket onMessage userId: {} 消息接收结束, userId); }OnMessage: 收到客户端信息时调用 ws实现功能关键部分 此处将整个游戏过程分割为三部分 分别为 匹配玩家 游戏中 游戏结束 3). 实现逻辑方法 1). 群发消息 sendMessageAll /*** 群发消息*/ private void sendMessageAll(MessageReply? messageReply) {log.info(ChatWebsocket sendMessageAll 消息群发开始 userId: {}, messageReply: {}, userId, JSON.toJSONString(messageReply));SetString receivers messageReply.getChatMessage().getReceivers();for (String receiver : receivers) {ChatWebsocket client matchCacheUtil.getClient(receiver);client.session.getAsyncRemote().sendText(JSON.toJSONString(messageReply));}log.info(ChatWebsocket sendMessageAll 消息群发结束 userId: {}, userId); }此方法根据形参 确定信息的发出者 并从工具类中 获取对方的webSocket对象 异步发送到对方的客户端中 2). 用户随机匹配对手 matchUser /*** 用户随机匹配对手*/SneakyThrows // 抛出异常注解private void matchUser(JSONObject jsonObject) {log.info(ChatWebsocket matchUser 用户随机匹配对手开始 message: {}, userId: {}, jsonObject.toJSONString(), userId);MessageReplyGameMatchInfo messageReply new MessageReply();ChatMessageGameMatchInfo result new ChatMessage();result.setSender(userId);result.setType(MessageTypeEnum.MATCH_USER);lock.lock();try {// 设置用户状态为匹配中 //            TODO 修改工具类的类型 使他不只能存储id 也能存储玩家的段位matchCacheUtil.setUserInMatch(userId);matchCond.signal();} finally {lock.unlock();}// 创建一个异步线程任务负责匹配其他同样处于匹配状态的其他用户Thread matchThread new Thread(() - {boolean flag  true;String receiver null;while (flag) {// 获取除自己以外的其他待匹配用户lock.lock();try {// 当前用户不处于待匹配状态 直接返回if (matchCacheUtil.getUserOnlineStatus(userId).compareTo(StatusEnum.IN_GAME) 0 //                            观察当前用户是否游戏中状态|| matchCacheUtil.getUserOnlineStatus(userId).compareTo(StatusEnum.GAME_OVER) 0) { //                        观察当前用户是否游戏结束 结算的状态log.info(ChatWebsocket matchUser 当前用户 {} 已退出匹配, userId);return;}// 当前用户取消匹配状态if (matchCacheUtil.getUserOnlineStatus(userId).compareTo(StatusEnum.IDLE) 0) {// 当前用户取消匹配messageReply.setCode(MessageCode.CANCEL_MATCH_ERROR.getCode());messageReply.setDesc(MessageCode.CANCEL_MATCH_ERROR.getDesc()); //                        设定返回信息 将从匹配中的状态该为待匹配SetString set  new HashSet();set.add(userId);result.setReceivers(set);result.setType(MessageTypeEnum.CANCEL_MATCH);messageReply.setChatMessage(result);log.info(ChatWebsocket matchUser 当前用户 {} 已退出匹配, userId); //                        发送返回信息sendMessageAll(messageReply);return;}//                    从room中获取对手的对象 这个receiver是对手的id //                    可以在这里下手脚 加一个while循环 判断直至找到相同段位的用户为止 //                    TODO 直接在setUserMatchRoom那块 加入玩家的段位信息 需要改动工具类String userDan competitionService.showPlayersExtraDan(Integer.parseInt(userId));while (true) {receiver matchCacheUtil.getUserInMatchRandom(userId); //                        这里必须把判空放在上面 否则如果是队列中没有人在匹配 却给receiver调用了Integer.parseInt(receiver)方法 会报空指针if (Objects.isNull(receiver))break;elseif (userDan.equals(competitionService.showPlayersExtraDan(Integer.parseInt(receiver))))break;}if (receiver ! null) {// 对手不处于待匹配状态if (matchCacheUtil.getUserOnlineStatus(receiver).compareTo(StatusEnum.IN_MATCH) ! 0) {log.info(ChatWebsocket matchUser 当前用户 {}, 匹配对手 {} 已退出匹配状态, userId, receiver);                    } else { //                            进了这个else就表明用户已经匹配到状态正常的对手了 //                            设定对手的基本信息matchCacheUtil.setUserInGame(userId);matchCacheUtil.setUserInGame(receiver); //                            将对手放入房间中 指定唯一usermatchCacheUtil.setUserInRoom(userId, receiver);flag  false; //                            匹配到了 令flag为false 跳出while循环 //                            此次匹配结束 进入开打状态}} else {// 如果当前没有待匹配用户进入等待队列try {log.info(ChatWebsocket matchUser 当前用户 {} 无对手可匹配, userId);matchCond.await();} catch (InterruptedException e) {log.error(ChatWebsocket matchUser 匹配线程 {} 发生异常: {},Thread.currentThread().getName(), e.getMessage());}}} finally {lock.unlock();}}log.info(已找到玩家 双方分别为  userId  和  receiver);UserMatchInfo senderInfo new UserMatchInfo();UserMatchInfo receiverInfo new UserMatchInfo();senderInfo.setUserId(userId);senderInfo.setScore(0);receiverInfo.setUserId(receiver);receiverInfo.setScore(0); //            两个对象分别记录两个玩家的得分matchCacheUtil.setUserMatchInfo(userId, JSON.toJSONString(senderInfo));matchCacheUtil.setUserMatchInfo(receiver, JSON.toJSONString(receiverInfo)); //            初始化接下来pk中玩家的信息 (每一道题提交答案完成都会 刷新一次对应的得分)GameMatchInfo gameMatchInfo new GameMatchInfo();//            获取玩家段位 根据玩家段位来获取题目String dan competitionService.showPlayersDan(Integer.parseInt(userId));ListQuestion questions questionService.getCompetitionQuestionsByDan(dan);gameMatchInfo.setQuestions(questions);gameMatchInfo.setSelfInfo(senderInfo);gameMatchInfo.setOpponentInfo(receiverInfo); //            一次性获取所有题目 //            存入此次对战中的当前玩家 对方 题目 //            一个GameMatchInfo就代表一个玩家的对象//            新增 存入此次pk中对方的用户名 头像UserWithValue userWithValue userService.showUser(Integer.parseInt(userId));String username userWithValue.getUser().getUsername();String userPic userWithValue.getUserValue().getPic();gameMatchInfo.setSelfUsername(username);gameMatchInfo.setSelfPicAvatar(userPic);UserWithValue receiverValue userService.showUser(Integer.parseInt(receiver));String receiverUsername receiverValue.getUser().getUsername();String opponentPic receiverValue.getUserValue().getPic();gameMatchInfo.setOpponentUsername(receiverUsername);gameMatchInfo.setOpponentPicAvatar(opponentPic);messageReply.setCode(MessageCode.SUCCESS.getCode());messageReply.setDesc(MessageCode.SUCCESS.getDesc()); //            确认返回信息的类型以及数据result.setData(gameMatchInfo);SetString set  new HashSet();set.add(userId);result.setReceivers(set);result.setType(MessageTypeEnum.MATCH_USER);messageReply.setChatMessage(result);sendMessageAll(messageReply);//            自己的传给自己的 对面的传给对面的gameMatchInfo.setSelfInfo(senderInfo);gameMatchInfo.setOpponentInfo(receiverInfo);result.setData(gameMatchInfo);set.clear();set.add(receiver);result.setReceivers(set);messageReply.setChatMessage(result);sendMessageAll(messageReply);log.info(ChatWebsocket matchUser 用户随机匹配对手结束 messageReply: {}, JSON.toJSONString(messageReply));}, MATCH_TASK_NAME_PREFIX userId);matchThread.start();}基本思路为 改变玩家状态为匹配中 并且匹配相同状态 相同段位的对手 (段位可按需增删) 匹配的过程是异步多线程匹配 若没有相同状态的对手 则线程沉睡 直至有对手匹配为止 (此处可以设置匹配超时时间进行优化) 确认对手状态无误后 根据id获取双方信息 此轮pk中题目 最后通过 sendMessageAll 的方法将信息发送给自己与对方 执行步骤见代码注释 3). 游戏中 toPlay /*** 游戏中*/SneakyThrowspublic void toPlay(JSONObject jsonObject) { //        每一道题提交了都会重新执行一次这个方法 //        (由答题方 执行)log.info(ChatWebsocket toPlay 用户更新对局信息开始 userId: {}, message: {}, userId, jsonObject.toJSONString());MessageReplyScoreSelectedInfo messageReply new MessageReply(); //        返回的信息类型//        下面的这个思路就是 从房间中找到对方 并且发送自己的分数更新信息给他ChatMessageScoreSelectedInfo result new ChatMessage();result.setSender(userId);String receiver matchCacheUtil.getUserFromRoom(userId); //        从房间中找出对面的对手是谁 发信息给他SetString set  new HashSet();set.add(receiver);result.setReceivers(set);result.setType(MessageTypeEnum.PLAY_GAME); //        设置消息的发送方 和 接收方 以及消息类型 (游戏中)//        获取新的得分 并且重新赋值给当前的user   (当前的user就是得分的那个)UserMatchChoice userMatchChoice jsonObject.getObject(data, UserMatchChoice.class);Integer newScore userMatchChoice.getUserScore();String userSelectedAnswer userMatchChoice.getUserSelectedAnswer();//        获取answerSituation对象 此对象中是所有正在游戏中的用户的回答信息 暂时存在这里answerSituationUtil.addAnswer(userId, userSelectedAnswer);UserMatchInfo userMatchInfo new UserMatchInfo();userMatchInfo.setUserId(userId);userMatchInfo.setScore(newScore);//        setUserMatchInfo所改变的数据是 同一时刻所有对战的用户的信息 //        在这里set是根据当前用户的id //        重新设置一下对应的用户对战信息matchCacheUtil.setUserMatchInfo(userId, JSON.toJSONString(userMatchInfo));//        设置响应数据的类型 //        更新 同时发送对面所选的选项result.setData(new ScoreSelectedInfo(userMatchInfo, userSelectedAnswer));messageReply.setCode(MessageCode.SUCCESS.getCode());messageReply.setDesc(MessageCode.SUCCESS.getDesc());messageReply.setChatMessage(result);//        返回包含当前用户的新信息的响应数据sendMessageAll(messageReply);log.info(ChatWebsocket toPlay 用户更新对局信息结束 userId: {}, userMatchInfo: {}, userId, JSON.toJSONString(userMatchInfo));}pk中 每一道题答完后 客户端往服务器发起的请求类型 主要思路是 根据信息的发出方 从redis中的房间机制获取他的对手 (在匹配的时候会将一轮对战中双方的id存入redis 可理解成放入房间 防止第三者客户端进入 对pk过程进行干扰) 之后将答题情况发送给对方 4). 游戏结束 gameover /*** 游戏结束*/public void gameover(JSONObject jsonObject) {log.info(ChatWebsocket gameover 用户对局结束 userId: {}, message: {}, userId, jsonObject.toJSONString());//        设置响应数据类型MessageReplyRoomAnswerSituation messageReply new MessageReply();//        设置响应数据 改变玩家的状态ChatMessageRoomAnswerSituation result new ChatMessage();result.setSender(userId);String receiver matchCacheUtil.getUserFromRoom(userId);result.setType(MessageTypeEnum.GAME_OVER);lock.lock();try { //            设定用户为游戏结束的状态matchCacheUtil.setUserGameover(userId);if (matchCacheUtil.getUserOnlineStatus(receiver).compareTo(StatusEnum.GAME_OVER) 0) {messageReply.setCode(MessageCode.SUCCESS.getCode());messageReply.setDesc(MessageCode.SUCCESS.getDesc());//        记录赢了的玩家的IDInteger winnerId jsonObject.getInteger(data);boolean isUpdate competitionService.updateUserStar(winnerId);if (!isUpdate) {messageReply.setCode(MessageCode.SYSTEM_ERROR.getCode());messageReply.setDesc(MessageCode.SYSTEM_ERROR.getDesc());}//                获取对战后的对战信息AnswerSituation selfAnswer answerSituationUtil.getAnswer(userId);AnswerSituation opponentAnswer answerSituationUtil.getAnswer(receiver);RoomAnswerSituation roomAnswerSituation new RoomAnswerSituation(userId, receiver, selfAnswer, opponentAnswer);result.setData(roomAnswerSituation);//                设置完结后的返回信息messageReply.setChatMessage(result);SetString set  new HashSet();set.add(receiver);result.setReceivers(set);sendMessageAll(messageReply); //                屎山会出手 两边全部发set.clear();set.add(userId);result.setReceivers(set);sendMessageAll(messageReply);//                移除属于游戏中的游戏信息matchCacheUtil.removeUserMatchInfo(userId);matchCacheUtil.removeUserFromRoom(userId);//                移除属于这一次的游戏选择信息answerSituationUtil.removeAnswer(userId);answerSituationUtil.removeAnswer(receiver);}} finally {lock.unlock();}log.info(ChatWebsocket gameover 对局 [{} - {}] 结束, userId, receiver);}代码中通过前端判断题目数组遍历完成 判断双方分数 发送gameover状态信息 前端通过比较双方总分 将胜利用户的id发回给后端 即此状态信息中的 T data 后端将其状态转换 并且将对应的双方此轮对战信息 包括总分 获胜者 对方的回答情况 发回给双方客户端 至此 一轮pk结束 5、配置类及工具类 1). WebSocket配置类 Configuration EnableWebSocket public class WebsocketConfig {Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();} }2). AnswerSituation 用户答题情况存储工具类 Component //用户答题情况 工具类 public class AnswerSituationUtil {private static final MapString, AnswerSituation ANSWER_SITUATION new HashMap();//    新增答案public void addAnswer(String userId,String answer){boolean isScored ANSWER_SITUATION.containsKey(userId);if (isScored)ANSWER_SITUATION.get(userId).getSelfAnswerSituations().add(answer);if (!isScored) {ArrayListString answers new ArrayList();answers.add(answer);ANSWER_SITUATION.put(userId,new AnswerSituation(answers));}}//    获取用户所有答案public AnswerSituation getAnswer(String userId){boolean isContain ANSWER_SITUATION.containsKey(userId);if (!isContain)return null;return ANSWER_SITUATION.get(userId);}//    移除答案public boolean removeAnswer(String userId){boolean isContain ANSWER_SITUATION.containsKey(userId);if (!isContain)returnfalse;ANSWER_SITUATION.remove(userId);returntrue;} }主要存储 记录 清除 用户每一轮答题的缓存 可优化存进 redis 中 3). MatchCacheUtil 存储用户在线状态及其客户端工具类 Component public class MatchCacheUtil {/*** 用户 userId 为 keyChatWebsocket 为 value*/private static final MapString, ChatWebsocket CLIENTS new HashMap();/*** key 是标识存储用户在线状态的 EnumRedisKeyvalue 为 map 类型其中用户 userId 为 key用户在线状态 为 value*/Resourceprivate RedisTemplateString, MapString, String redisTemplate;/*** 添加客户端*/public void addClient(String userId, ChatWebsocket websocket) {CLIENTS.put(userId, websocket);}/*** 移除客户端*/public void removeClinet(String userId) {CLIENTS.remove(userId);}/*** 获取客户端*/public ChatWebsocket getClient(String userId) {return CLIENTS.get(userId);}/*** 移除用户在线状态*/public void removeUserOnlineStatus(String userId) {redisTemplate.opsForHash().delete(EnumRedisKey.USER_STATUS.getKey(), userId);}/*** 获取用户在线状态*/public StatusEnum getUserOnlineStatus(String userId) {Object status redisTemplate.opsForHash().get(EnumRedisKey.USER_STATUS.getKey(), userId);if (status null) {return null;}return StatusEnum.getStatusEnum(status.toString());}/*** 设置用户为 IDLE 状态*/public void setUserIDLE(String userId) {removeUserOnlineStatus(userId);redisTemplate.opsForHash().put(EnumRedisKey.USER_STATUS.getKey(), userId, StatusEnum.IDLE.getValue());}/*** 设置用户为 IN_MATCH 状态*/public void setUserInMatch(String userId) {removeUserOnlineStatus(userId);redisTemplate.opsForHash().put(EnumRedisKey.USER_STATUS.getKey(), userId, StatusEnum.IN_MATCH.getValue());}/*** 随机获取处于匹配状态的用户除了指定用户外*/public String getUserInMatchRandom(String userId) {OptionalMap.EntryObject, Object any redisTemplate.opsForHash().entries(EnumRedisKey.USER_STATUS.getKey()).entrySet().stream().filter(entry - entry.getValue().equals(StatusEnum.IN_MATCH.getValue()) !entry.getKey().equals(userId)).findAny();return any.map(entry - entry.getKey().toString()).orElse(null);}/*** 设置用户为 IN_GAME 状态*/public void setUserInGame(String userId) {removeUserOnlineStatus(userId);redisTemplate.opsForHash().put(EnumRedisKey.USER_STATUS.getKey(), userId, StatusEnum.IN_GAME.getValue());}/*** 设置处于游戏中的用户在同一房间*/public void setUserInRoom(String userId1, String userId2) {redisTemplate.opsForHash().put(EnumRedisKey.ROOM.getKey(), userId1, userId2);redisTemplate.opsForHash().put(EnumRedisKey.ROOM.getKey(), userId2, userId1);}/*** 从房间中移除用户*/public void removeUserFromRoom(String userId) {redisTemplate.opsForHash().delete(EnumRedisKey.ROOM.getKey(), userId);}/*** 从房中获取用户*/public String getUserFromRoom(String userId) {return redisTemplate.opsForHash().get(EnumRedisKey.ROOM.getKey(), userId).toString();}/*** 设置处于游戏中的用户的对战信息*/public void setUserMatchInfo(String userId, String userMatchInfo) {redisTemplate.opsForHash().put(EnumRedisKey.USER_MATCH_INFO.getKey(), userId, userMatchInfo);}/*** 移除处于游戏中的用户的对战信息*/public void removeUserMatchInfo(String userId) {redisTemplate.opsForHash().delete(EnumRedisKey.USER_MATCH_INFO.getKey(), userId);}/*** 设置处于游戏中的用户的对战信息*/public String getUserMatchInfo(String userId) {return redisTemplate.opsForHash().get(EnumRedisKey.USER_MATCH_INFO.getKey(), userId).toString();}/*** 设置用户为游戏结束状态*/public synchronized void setUserGameover(String userId) {removeUserOnlineStatus(userId);redisTemplate.opsForHash().put(EnumRedisKey.USER_STATUS.getKey(), userId, StatusEnum.GAME_OVER.getValue());} }设置并改变用户的在线状态 利用redis 枚举类 在每一轮游戏结束之后 将其移除缓存 4). MessageCode 响应码 Getter public enum MessageCode {/*** 响应码*/SUCCESS(2000, 连接成功),USER_IS_ONLINE(2001, 用户已存在),CURRENT_USER_IS_INGAME(2002, 当前用户已在游戏中),MESSAGE_ERROR(2003, 消息错误),CANCEL_MATCH_ERROR(2004, 用户取消了匹配),SYSTEM_ERROR(2005,系统错误);private final Integer code;private final String desc;MessageCode(Integer code, String desc) {this.code code;this.desc desc;} }枚举类定义封装ws使用中会出现的错误 5). MessageTypeEnum 用户状态枚举类 public enum MessageTypeEnum {/*** 匹配对手*/MATCH_USER,/*** 游戏开始*/PLAY_GAME,/*** 游戏结束*/GAME_OVER, }枚举类统一定义ws连接中OnMessage中会出现的消息类型 前后端根据判断消息类型 判断执行的逻辑 和方法执行的阶段 6). StatusEnum 用户状态枚举类 public enum StatusEnum {/*** 待匹配*/IDLE,/*** 匹配中*/IN_MATCH,/*** 游戏中*/IN_GAME,/*** 游戏结束*/GAME_OVER,;public static StatusEnum getStatusEnum(String status) {switch (status) {caseIDLE:return IDLE;caseIN_MATCH:return IN_MATCH;caseIN_GAME:return IN_GAME;caseGAME_OVER:return GAME_OVER;default:throw new GameServerException(GameServerError.MESSAGE_TYPE_ERROR);}}public String getValue() {return this.name();} }确认用户此时的状态 为 匹配中 待匹配 游戏中 游戏结束 注用户的状态 ≠ 消息类
http://www.dnsts.com.cn/news/206566.html

相关文章:

  • 新乡 网站运营房地产网站建设流程
  • 个人备案域名可以做企业网站吗图片论播wordpress
  • 效果好企业营销型网站建设百度推广公司怎么代理到的
  • 哪个网站上可以做初中数学题购物网站用那个软件做
  • 温岭建设局网站wordpress设置菜单导航
  • 企业门户网站的意义一站式服务门户
  • 网站一级域名长春建站公众号
  • 四平网站制作网站的二级网页关键词
  • 买手表网站深圳网站软件网站建设
  • 无锡做网站365caiyi最新做做网站
  • 有机农产品网站开发方案网站关键词设置数量
  • 网站建设团队与分工搭建网站有哪些
  • 网站建设 报价单 doc遵义网络推广软文
  • 三亚网站建设公司前端招聘去哪个网站
  • 建设银行鹤岗分行网站企业解决单身问题方案
  • 网站建设目的功能绿色学校网站模板
  • 私人定制平台网站网络安全公司有哪些
  • 佛山网站制作建设做期货都看哪个网站
  • 网站后台模版dw软件怎么下载
  • 杭州网站设计手机常用网站建设软件有哪些
  • 旅游网站建设课程设计报告北京市建设工程质监站网站
  • 网站301重定向WordPress手动切换主题
  • 网站建设上如何提高市场竞争力建设网站需要什么
  • 网站模板下载软件网站录屏可以做证据吗
  • 网站企业案例广东官网建设公司
  • 宜春网站建设公司联系方式工作组赴福建莆田
  • 怎么给自己网站做搜索框制作企业网站的报告
  • 购物商城网站开发网站服务流程
  • 小程序源码1200套邯郸整站优化
  • 网站被k了怎么办东莞市建设工程网站