成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

netty搭建web聊天室(3)單聊

Lavender / 1668人閱讀

摘要:開始聊天發(fā)送聊天信息時(shí)消息,這樣后端就知道是誰要發(fā)給誰,根據(jù)用戶名去找到具體的線程去多帶帶推送消息,實(shí)現(xiàn)單聊。前端待完善左側(cè)聊天列表沒有實(shí)現(xiàn),每搜索一個(gè)在線用戶,應(yīng)該動(dòng)態(tài)顯示在左側(cè),點(diǎn)擊該用戶,動(dòng)態(tài)顯示右側(cè)聊天窗口進(jìn)行消息發(fā)送。

上節(jié)課講了群聊,這次來說說單聊,單聊要比群聊復(fù)雜點(diǎn),但是代碼也不是很多,主要是前端顯示比較麻煩點(diǎn)。

效果:

登陸

首先一個(gè)新的用戶,需要先登陸,輸入自己的昵稱,然后點(diǎn)擊登陸。后端服務(wù)會(huì)把你的用戶名和當(dāng)前的線程進(jìn)行邦定,這樣就可以通過你的用戶名找到你的線程。登陸成功,后端返回定義好的消息 success,前端判斷記錄CHAT.me,這樣給別人發(fā)消息時(shí)就可以攜帶自己的信息。

查找用戶

在輸入框輸入用戶名,就可以返回對應(yīng)的用戶的線程,這樣你就可以把消息發(fā)送給你要聊天的對象。如果不存在,后端回返回消息給前端,該用戶不存在。如果存在,就記錄此用戶名到CHAT.to中,這樣你發(fā)送消息的時(shí)候就可以發(fā)送給對應(yīng)用戶了。

開始聊天

發(fā)送聊天信息時(shí)me:to:消息,這樣后端就知道是誰要發(fā)給誰,根據(jù)用戶名去找到具體的線程去多帶帶推送消息,實(shí)現(xiàn)單聊。

前端待完善

左側(cè)聊天列表沒有實(shí)現(xiàn),每搜索一個(gè)在線用戶,應(yīng)該動(dòng)態(tài)顯示在左側(cè),點(diǎn)擊該用戶,動(dòng)態(tài)顯示右側(cè)聊天窗口進(jìn)行消息發(fā)送?,F(xiàn)在是你和所有人的單聊消息都會(huì)顯示在右側(cè),沒有完成拆分,因?yàn)檫@是一個(gè)頁面,處理起來比較麻煩,我一個(gè)后端就不花時(shí)間搞了,感興趣的可以自己去實(shí)現(xiàn)。

前端代碼

因?yàn)樽⒁暠容^詳細(xì),就直接復(fù)制整個(gè)代碼到這里,大家自己看。



  
    
    單人聊天
    
    
  
  

    

mike單人聊天室,等你來聊



后端改造

加入一個(gè)UserMap,邦定user和Channel

package netty;

import java.util.HashMap;
import java.util.Map;

import io.netty.channel.Channel;

/**
 * The class UserMap
 */
public class UserMap {
  private HashMap users = new HashMap();
  private static UserMap instance;
  
  public static UserMap getInstance () {
      if (instance == null) {
          instance = new UserMap();
      }
      return instance;
  }
  
  private UserMap () {
      
  }
  public void addUser(String userId, Channel ch) {
      this.users.put(userId, ch);
  }
  
  public Channel getUser (String userId) {
      return this.users.get(userId);
  }
  
  public void deleteUser (Channel ch) {
      for (Map.Entry map: users.entrySet()) {
        if (map.getValue() == ch) {
            users.remove(map.getKey());
            break;
        }
    }
  }
}

ChatHandler改造

package netty;

import java.time.LocalDateTime;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * 
 */
public class ChatHandler extends SimpleChannelInboundHandler{
    
    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    public static UserMap usermap = UserMap.getInstance();
    /**
     * 每當(dāng)從服務(wù)端收到新的客戶端連接時(shí),客戶端的 Channel 存入ChannelGroup列表中,并通知列表中的其他客戶端 Channel
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入
");
        }
        channels.add(ctx.channel());
    }
    
    /**
     * 每當(dāng)從服務(wù)端收到客戶端斷開時(shí),客戶端的 Channel 移除 ChannelGroup 列表中,并通知列表中的其他客戶端 Channel
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 離開
");
        }
        channels.remove(ctx.channel());
    }
    
    /**
     * 會(huì)話建立時(shí)
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
        Channel incoming = ctx.channel();
        System.out.println("ChatClient:"+incoming.remoteAddress()+"在線");
    }
    
    /**
     * 會(huì)話結(jié)束時(shí)
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
        Channel incoming = ctx.channel();
        System.out.println("ChatClient:"+incoming.remoteAddress()+"掉線");
        //清除離線用戶
        this.usermap.deleteUser(incoming);
    }
    
    /**
     * 出現(xiàn)異常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)
        Channel incoming = ctx.channel();
        System.out.println("ChatClient:"+incoming.remoteAddress()+"異常");
        // 當(dāng)出現(xiàn)異常就關(guān)閉連接
        cause.printStackTrace();
        ctx.close();
    }
    
    /**
     * 讀取客戶端發(fā)送的消息,并將信息轉(zhuǎn)發(fā)給其他客戶端的 Channel。
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object  request) throws Exception {
           if (request instanceof FullHttpRequest) { //是http請求
               FullHttpResponse response = new DefaultFullHttpResponse(
                        HttpVersion.HTTP_1_1,HttpResponseStatus.OK , Unpooled.wrappedBuffer("Hello netty"
                                .getBytes()));
                response.headers().set("Content-Type", "text/plain");
                response.headers().set("Content-Length", response.content().readableBytes());
                response.headers().set("connection", HttpHeaderValues.KEEP_ALIVE);
                ctx.channel().writeAndFlush(response);
           } else if (request instanceof TextWebSocketFrame) { // websocket請求
               //此處id為neety自動(dòng)分配給每個(gè)對話線程的id,有兩種,一個(gè)長id一個(gè)短id,長id唯一,短id可能會(huì)重復(fù)
               String userId = ctx.channel().id().asLongText();
               //客戶端發(fā)送過來的消息
               String msg = ((TextWebSocketFrame)request).text();
               System.out.println("收到客戶端"+userId+":"+msg);
               
               //發(fā)送消息給所有客戶端  群聊
               //channels.writeAndFlush(new TextWebSocketFrame(msg));
            
               
               
               // 邦定user和channel 
               // 定義每個(gè)上線用戶主動(dòng)發(fā)送初始化信息過來,攜帶自己的name,然后完成綁定  模型  init:[usrname]
               // 實(shí)際場景中應(yīng)該使用user唯一id
              if (msg.indexOf("init") != -1) {
                String userNames[] = msg.split(":");
                if ("init".equals(userNames[0])) { // 記錄新的用戶
                    this.usermap.addUser(userNames[1].trim(), ctx.channel());
                    ctx.channel().writeAndFlush(new TextWebSocketFrame("success"));
                }
              }
              
                
                //搜索在線用戶      消息模型  search:[username]
                if (msg.indexOf("search") != -1) {
                    Channel ch = this.usermap.getUser(msg.split(":")[1].trim());
                    if (ch != null) { //此用戶存在
                        ctx.channel().writeAndFlush(new TextWebSocketFrame("search:"+msg.split(":")[1].trim()+":已找到"));
                    } else { // 此用戶不存在
                        ctx.channel().writeAndFlush(new TextWebSocketFrame("search:"+msg.split(":")[1].trim()+":未找到"));
                    }
                    
                }
               
               //發(fā)送消息給指定的用戶    消息模型  me:to:[msg]
                if (msg.split(":").length == 3) {  //判斷是單聊消息
                    this.usermap.getUser(msg.split(":")[1].trim()).writeAndFlush(new TextWebSocketFrame(msg));
                }
                
               //ctx.channel().writeAndFlush(new TextWebSocketFrame(((TextWebSocketFrame)request).text()));
           }
    }

}

注釋很詳細(xì),自己看

總結(jié)

消息模型應(yīng)該定義一個(gè)多帶帶的類來管理,我目前是用的String字符串來判斷,提前規(guī)定了一些模型,通過判斷來響應(yīng)前端的請求,比較簡單。還有就是沒有使用數(shù)據(jù)庫,前端不能顯示聊天記錄,不能實(shí)現(xiàn)消息的已讀未讀。實(shí)際場景中應(yīng)該對消息進(jìn)行加密存儲(chǔ),且不能窺探用戶隱私。
前端可以使用localstorage來存儲(chǔ)聊天記錄,自己可以擴(kuò)展。
前端的顯示可能有點(diǎn)問題,自己可以調(diào)。其實(shí)主要是學(xué)習(xí)netty后端的搭建

別忘了關(guān)注我 mike啥都想搞

求關(guān)注啊。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/101348.html

相關(guān)文章

  • netty搭建web天室(1)

    摘要:提供異步的事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架和工具,用以快速開發(fā)高性能高可靠性的網(wǎng)絡(luò)服務(wù)器和客戶端程序??偨Y(jié)我們完成了服務(wù)端的簡單搭建,模擬了聊天會(huì)話場景。 之前一直在搞前端的東西,都快忘了自己是個(gè)java開發(fā)。其實(shí)還有好多java方面的東西沒搞過,突然了解到netty,覺得有必要學(xué)一學(xué)。 介紹 Netty是由JBOSS提供的一個(gè)java開源框架。Netty提供異步的、事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框...

    izhuhaodev 評論0 收藏0
  • netty搭建web天室(2)群聊

    摘要:上節(jié)課完成了的后端搭建,搞定了簡單的請求響應(yīng),今天來結(jié)合前端來完成群聊功能。其實(shí)后端群聊很簡單,就是把一個(gè)用戶的輸入消息,返回給所有在線客戶端,前端去負(fù)責(zé)篩選顯示。 上節(jié)課完成了netty的后端搭建,搞定了簡單的http請求響應(yīng),今天來結(jié)合前端websocket來完成群聊功能。話不多說先上圖:showImg(https://segmentfault.com/img/bVbnCa8?w=...

    microelec 評論0 收藏0
  • swoole 超簡單 構(gòu)建天室.資辭 群聊,組聊,單聊.

    摘要:今天來做一個(gè)簡單的聊天室支持換房間支持私信的寫的代碼有點(diǎn)渣里面有很多不是很好的地方畢竟我只是一個(gè)野生程序猿環(huán)境地址樣子差不多是這個(gè)樣子的我不想把代碼發(fā)到我的服務(wù)器上因?yàn)檫@個(gè)項(xiàng)目太小了很垃圾而且怕被攻擊這里有錄的一個(gè)演示視頻沒有廣告的你們可以 今天來做一個(gè)簡單的聊天室,支持換房間,支持私信的. 寫的代碼有點(diǎn)渣,里面有很多不是很好的地方.畢竟我只是一個(gè)野生程序猿. 環(huán)境: php7.0...

    Towers 評論0 收藏0

發(fā)表評論

0條評論

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