摘要:實現聊天,項目介紹。本章完整代碼鏈接。本章主要講的是聊天中關于聊天功能的實現。移除方法與處理異常方法的重寫在中重寫其移除的方法,以及處理異常的方法。用戶手機端獲取未簽收的消息列表判斷不能為空查詢列表測試
Netty+SpringBoot+FastDFS+Html5實現聊天App,項目介紹。
Netty+SpringBoot+FastDFS+Html5實現聊天App,項目github鏈接。
本章完整代碼鏈接。
本章主要講的是聊天App_PigChat中關于聊天功能的實現。
移除方法與處理異常方法的重寫在ChatHandler中重寫其移除channel的方法handlerRemoved,以及處理異常的方法exceptionCaught。
@Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { String channelId = ctx.channel().id().asShortText(); System.out.println("客戶端被移除,channelId為:" + channelId); // 當觸發handlerRemoved,ChannelGroup會自動移除對應客戶端的channel users.remove(ctx.channel()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); // 發生異常之后關閉連接(關閉channel),隨后從ChannelGroup中移除 ctx.channel().close(); users.remove(ctx.channel()); }定義消息的實體類
public class ChatMsg implements Serializable { private static final long serialVersionUID = 3611169682695799175L; private String senderId; // 發送者的用戶id private String receiverId; // 接受者的用戶id private String msg; // 聊天內容 private String msgId; // 用于消息的簽收 public String getSenderId() { return senderId; } public void setSenderId(String senderId) { this.senderId = senderId; } public String getReceiverId() { return receiverId; } public void setReceiverId(String receiverId) { this.receiverId = receiverId; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getMsgId() { return msgId; } public void setMsgId(String msgId) { this.msgId = msgId; } }
對實體類再做一層包裝
public class DataContent implements Serializable { private static final long serialVersionUID = 8021381444738260454L; private Integer action; // 動作類型 private ChatMsg chatMsg; // 用戶的聊天內容entity private String extand; // 擴展字段 public Integer getAction() { return action; } public void setAction(Integer action) { this.action = action; } public ChatMsg getChatMsg() { return chatMsg; } public void setChatMsg(ChatMsg chatMsg) { this.chatMsg = chatMsg; } public String getExtand() { return extand; } public void setExtand(String extand) { this.extand = extand; } }定義發送消息的動作的枚舉類型
public enum MsgActionEnum { CONNECT(1, "第一次(或重連)初始化連接"), CHAT(2, "聊天消息"), SIGNED(3, "消息簽收"), KEEPALIVE(4, "客戶端保持心跳"), PULL_FRIEND(5, "拉取好友"); public final Integer type; public final String content; MsgActionEnum(Integer type, String content){ this.type = type; this.content = content; } public Integer getType() { return type; } }
/** * @Description: 用戶id和channel的關聯關系處理 */ public class UserChannelRel { private static HashMap接受與處理消息方法的重寫manager = new HashMap<>(); public static void put(String senderId, Channel channel) { manager.put(senderId, channel); } public static Channel get(String senderId) { return manager.get(senderId); } public static void output() { for (HashMap.Entry entry : manager.entrySet()) { System.out.println("UserId: " + entry.getKey() + ", ChannelId: " + entry.getValue().id().asLongText()); } } }
重寫ChatHandler讀取消息的channelRead0方法。
具體步驟如下:
(1)獲取客戶端發來的消息;
(2)判斷消息類型,根據不同的類型來處理不同的業務;
(2.1)當websocket 第一次open的時候,初始化channel,把用的channel和userid關聯起來;
(2.2)聊天類型的消息,把聊天記錄保存到數據庫,同時標記消息的簽收狀態[未簽收];
然后實現消息的發送,首先從全局用戶Channel關系中獲取接受方的channel,然后當receiverChannel不為空的時候,從ChannelGroup去查找對應的channel是否存在,若用戶在線,則使用writeAndFlush方法向其發送消息;
(2.3)簽收消息類型,針對具體的消息進行簽收,修改數據庫中對應消息的簽收狀態[已簽收];
(2.4)心跳類型的消息
// 用于記錄和管理所有客戶端的channle public static ChannelGroup users = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { System.out.println("read.........."); // 獲取客戶端傳輸過來的消息 String content = msg.text(); Channel currentChannel = ctx.channel(); // 1. 獲取客戶端發來的消息 DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class); Integer action = dataContent.getAction(); // 2. 判斷消息類型,根據不同的類型來處理不同的業務 if (action == MsgActionEnum.CONNECT.type) { // 2.1 當websocket 第一次open的時候,初始化channel,把用的channel和userid關聯起來 String senderId = dataContent.getChatMsg().getSenderId(); UserChannelRel.put(senderId, currentChannel); // 測試 for (Channel c : users) { System.out.println(c.id().asLongText()); } UserChannelRel.output(); } else if (action == MsgActionEnum.CHAT.type) { // 2.2 聊天類型的消息,把聊天記錄保存到數據庫,同時標記消息的簽收狀態[未簽收] ChatMsg chatMsg = dataContent.getChatMsg(); String msgText = chatMsg.getMsg(); String receiverId = chatMsg.getReceiverId(); String senderId = chatMsg.getSenderId(); // 保存消息到數據庫,并且標記為 未簽收 UserService userService = (UserService)SpringUtil.getBean("userServiceImpl"); String msgId = userService.saveMsg(chatMsg); chatMsg.setMsgId(msgId); DataContent dataContentMsg = new DataContent(); dataContentMsg.setChatMsg(chatMsg); // 發送消息 // 從全局用戶Channel關系中獲取接受方的channel Channel receiverChannel = UserChannelRel.get(receiverId); if (receiverChannel == null) { // TODO channel為空代表用戶離線,推送消息(JPush,個推,小米推送) } else { // 當receiverChannel不為空的時候,從ChannelGroup去查找對應的channel是否存在 Channel findChannel = users.find(receiverChannel.id()); if (findChannel != null) { // 用戶在線 receiverChannel.writeAndFlush( new TextWebSocketFrame( JsonUtils.objectToJson(dataContentMsg))); } else { // 用戶離線 TODO 推送消息 } } } else if (action == MsgActionEnum.SIGNED.type) { // 2.3 簽收消息類型,針對具體的消息進行簽收,修改數據庫中對應消息的簽收狀態[已簽收] UserService userService = (UserService)SpringUtil.getBean("userServiceImpl"); // 擴展字段在signed類型的消息中,代表需要去簽收的消息id,逗號間隔 String msgIdsStr = dataContent.getExtand(); String msgIds[] = msgIdsStr.split(","); List獲取未簽收的消息列表的接口msgIdList = new ArrayList<>(); for (String mid : msgIds) { if (StringUtils.isNotBlank(mid)) { msgIdList.add(mid); } } System.out.println(msgIdList.toString()); if (msgIdList != null && !msgIdList.isEmpty() && msgIdList.size() > 0) { // 批量簽收 userService.updateMsgSigned(msgIdList); } } else if (action == MsgActionEnum.KEEPALIVE.type) { // 2.4 心跳類型的消息 System.out.println("收到來自channel為[" + currentChannel + "]的心跳包..."); } }
在controller中添加獲取未簽收的消息列表的接口getUnReadMsgList。
/** * * @Description: 用戶手機端獲取未簽收的消息列表 */ @PostMapping("/getUnReadMsgList") public IMoocJSONResult getUnReadMsgList(String acceptUserId) { // 0. userId 判斷不能為空 if (StringUtils.isBlank(acceptUserId)) { return IMoocJSONResult.errorMsg(""); } // 查詢列表 List測試unreadMsgList = userService.getUnReadMsgList(acceptUserId); return IMoocJSONResult.ok(unreadMsgList); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73307.html
Netty+SpringBoot+FastDFS+Html5實現聊天App,項目介紹。Netty+SpringBoot+FastDFS+Html5實現聊天App,項目github鏈接。本章完整代碼鏈接。 本章內容 (1) 查詢好友列表的接口 (2)通過或忽略好友請求的接口 (3)添加好友功能展示 查詢好友列表的接口 /** * @Description: 查詢我的好友列表 ...
閱讀 2255·2021-11-23 09:51
閱讀 1048·2021-11-18 10:02
閱讀 3441·2021-10-13 09:49
閱讀 1269·2021-09-22 14:57
閱讀 10462·2021-08-18 10:20
閱讀 1185·2019-08-30 15:55
閱讀 2232·2019-08-29 16:06
閱讀 3237·2019-08-29 11:14