国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App(五)

oneasp / 1869人閱讀

摘要:實(shí)現(xiàn)聊天,項(xiàng)目介紹。本章完整代碼鏈接。本章主要講的是聊天中關(guān)于聊天功能的實(shí)現(xiàn)。移除方法與處理異常方法的重寫(xiě)在中重寫(xiě)其移除的方法,以及處理異常的方法。用戶(hù)手機(jī)端獲取未簽收的消息列表判斷不能為空查詢(xún)列表測(cè)試

Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目介紹。

Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目github鏈接。

本章完整代碼鏈接。

本章主要講的是聊天App_PigChat中關(guān)于聊天功能的實(shí)現(xiàn)。

移除方法與處理異常方法的重寫(xiě)

在ChatHandler中重寫(xiě)其移除channel的方法handlerRemoved,以及處理異常的方法exceptionCaught。

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        
        String channelId = ctx.channel().id().asShortText();
        System.out.println("客戶(hù)端被移除,channelId為:" + channelId);
        
        // 當(dāng)觸發(fā)handlerRemoved,ChannelGroup會(huì)自動(dòng)移除對(duì)應(yīng)客戶(hù)端的channel
        users.remove(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        // 發(fā)生異常之后關(guān)閉連接(關(guān)閉channel),隨后從ChannelGroup中移除
        ctx.channel().close();
        users.remove(ctx.channel());
    }
定義消息的實(shí)體類(lèi)
public class ChatMsg implements Serializable {

    private static final long serialVersionUID = 3611169682695799175L;
    
    private String senderId;        // 發(fā)送者的用戶(hù)id    
    private String receiverId;        // 接受者的用戶(hù)id
    private String msg;                // 聊天內(nèi)容
    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;
    }
    
}

對(duì)實(shí)體類(lèi)再做一層包裝

public class DataContent implements Serializable {

    private static final long serialVersionUID = 8021381444738260454L;

    private Integer action;        // 動(dòng)作類(lèi)型
    private ChatMsg chatMsg;    // 用戶(hù)的聊天內(nèi)容entity
    private String extand;        // 擴(kuò)展字段
    
    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;
    }
}
定義發(fā)送消息的動(dòng)作的枚舉類(lèi)型
public enum MsgActionEnum {
    
    CONNECT(1, "第一次(或重連)初始化連接"),
    CHAT(2, "聊天消息"),    
    SIGNED(3, "消息簽收"),
    KEEPALIVE(4, "客戶(hù)端保持心跳"),
    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;
    }  
}



定義記錄用戶(hù)與channel關(guān)系的類(lèi)
/**
 * @Description: 用戶(hù)id和channel的關(guān)聯(lián)關(guān)系處理
 */
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());
        }
    }
}
接受與處理消息方法的重寫(xiě)

重寫(xiě)ChatHandler讀取消息的channelRead0方法。

具體步驟如下:

(1)獲取客戶(hù)端發(fā)來(lái)的消息;

(2)判斷消息類(lèi)型,根據(jù)不同的類(lèi)型來(lái)處理不同的業(yè)務(wù);

(2.1)當(dāng)websocket 第一次open的時(shí)候,初始化channel,把用的channel和userid關(guān)聯(lián)起來(lái);

(2.2)聊天類(lèi)型的消息,把聊天記錄保存到數(shù)據(jù)庫(kù),同時(shí)標(biāo)記消息的簽收狀態(tài)[未簽收];
然后實(shí)現(xiàn)消息的發(fā)送,首先從全局用戶(hù)Channel關(guān)系中獲取接受方的channel,然后當(dāng)receiverChannel不為空的時(shí)候,從ChannelGroup去查找對(duì)應(yīng)的channel是否存在,若用戶(hù)在線,則使用writeAndFlush方法向其發(fā)送消息;

(2.3)簽收消息類(lèi)型,針對(duì)具體的消息進(jìn)行簽收,修改數(shù)據(jù)庫(kù)中對(duì)應(yīng)消息的簽收狀態(tài)[已簽收];

(2.4)心跳類(lèi)型的消息

    // 用于記錄和管理所有客戶(hù)端的channle
    public static ChannelGroup users = 
            new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) 
            throws Exception {
        System.out.println("read..........");
        // 獲取客戶(hù)端傳輸過(guò)來(lái)的消息
        String content = msg.text();
        
        Channel currentChannel = ctx.channel();

        // 1. 獲取客戶(hù)端發(fā)來(lái)的消息
        DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class);
        Integer action = dataContent.getAction();
        // 2. 判斷消息類(lèi)型,根據(jù)不同的類(lèi)型來(lái)處理不同的業(yè)務(wù)

        if (action == MsgActionEnum.CONNECT.type) {
            //     2.1  當(dāng)websocket 第一次open的時(shí)候,初始化channel,把用的channel和userid關(guān)聯(lián)起來(lái)
            String senderId = dataContent.getChatMsg().getSenderId();
            UserChannelRel.put(senderId, currentChannel);
            
            // 測(cè)試
            for (Channel c : users) {
                System.out.println(c.id().asLongText());
            }
            UserChannelRel.output();
        } else if (action == MsgActionEnum.CHAT.type) {
            //  2.2  聊天類(lèi)型的消息,把聊天記錄保存到數(shù)據(jù)庫(kù),同時(shí)標(biāo)記消息的簽收狀態(tài)[未簽收]
            ChatMsg chatMsg = dataContent.getChatMsg();
            String msgText = chatMsg.getMsg();
            String receiverId = chatMsg.getReceiverId();
            String senderId = chatMsg.getSenderId();
            
            // 保存消息到數(shù)據(jù)庫(kù),并且標(biāo)記為 未簽收
            UserService userService = (UserService)SpringUtil.getBean("userServiceImpl");
            String msgId = userService.saveMsg(chatMsg);
            chatMsg.setMsgId(msgId);
            
            DataContent dataContentMsg = new DataContent();
            dataContentMsg.setChatMsg(chatMsg);
            
            // 發(fā)送消息
            // 從全局用戶(hù)Channel關(guān)系中獲取接受方的channel
            Channel receiverChannel = UserChannelRel.get(receiverId);
            if (receiverChannel == null) {
                // TODO channel為空代表用戶(hù)離線,推送消息(JPush,個(gè)推,小米推送)
            } else {
                // 當(dāng)receiverChannel不為空的時(shí)候,從ChannelGroup去查找對(duì)應(yīng)的channel是否存在
                Channel findChannel = users.find(receiverChannel.id());
                if (findChannel != null) {
                    // 用戶(hù)在線
                    receiverChannel.writeAndFlush(
                            new TextWebSocketFrame(
                                    JsonUtils.objectToJson(dataContentMsg)));
                } else {
                    // 用戶(hù)離線 TODO 推送消息
                }
            }
            
        } else if (action == MsgActionEnum.SIGNED.type) {
            //  2.3  簽收消息類(lèi)型,針對(duì)具體的消息進(jìn)行簽收,修改數(shù)據(jù)庫(kù)中對(duì)應(yīng)消息的簽收狀態(tài)[已簽收]
            UserService userService = (UserService)SpringUtil.getBean("userServiceImpl");
            // 擴(kuò)展字段在signed類(lèi)型的消息中,代表需要去簽收的消息id,逗號(hào)間隔
            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  心跳類(lèi)型的消息
            System.out.println("收到來(lái)自channel為[" + currentChannel + "]的心跳包...");
        }
    }
    
獲取未簽收的消息列表的接口

在controller中添加獲取未簽收的消息列表的接口getUnReadMsgList。

    /**
     * 
     * @Description: 用戶(hù)手機(jī)端獲取未簽收的消息列表
     */
    @PostMapping("/getUnReadMsgList")
    public IMoocJSONResult getUnReadMsgList(String acceptUserId) {
        // 0. userId 判斷不能為空
        if (StringUtils.isBlank(acceptUserId)) {
            return IMoocJSONResult.errorMsg("");
        }
        
        // 查詢(xún)列表
        List unreadMsgList = userService.getUnReadMsgList(acceptUserId);
        
        return IMoocJSONResult.ok(unreadMsgList);
    }
測(cè)試

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/73307.html

相關(guān)文章

  • Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App詳解(四)

    Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目介紹。Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目github鏈接。本章完整代碼鏈接。 本章內(nèi)容 (1) 查詢(xún)好友列表的接口 (2)通過(guò)或忽略好友請(qǐng)求的接口 (3)添加好友功能展示 查詢(xún)好友列表的接口 /** * @Description: 查詢(xún)我的好友列表 ...

    why_rookie 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<