最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實戰(zhàn)之用springboot+netty實現(xiàn)簡單的一對一聊天

 更新時間:2021年04月25日 11:38:02   作者:caiyang2015  
這篇文章主要介紹了Java實戰(zhàn)之用springboot+netty實現(xiàn)簡單的一對一聊天,文中有非常詳細的代碼示例,對正在學(xué)習(xí)Java的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、引入pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.chat.info</groupId>
    <artifactId>chat-server</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.33.Final</version>
        </dependency>
 
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>
 
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

二、創(chuàng)建netty 服務(wù)端

package com.chat.server;
 
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
 
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
 
@Component
@Slf4j
public class ChatServer {
 
    private EventLoopGroup bossGroup;
    private EventLoopGroup workGroup;
 
    private void run() throws Exception {
        log.info("開始啟動聊天服務(wù)器");
        bossGroup = new NioEventLoopGroup(1);
        workGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChatServerInitializer());
            //啟動服務(wù)器
            ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
            log.info("開始啟動聊天服務(wù)器結(jié)束");
            channelFuture.channel().closeFuture().sync();
 
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
 
    }
 
    /**
     * 初始化服務(wù)器
     */
    @PostConstruct()
    public void init() {
        new Thread(() -> {
            try {
                run();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }
 
 
    @PreDestroy
    public void destroy() throws InterruptedException {
        if (bossGroup != null) {
            bossGroup.shutdownGracefully().sync();
        }
        if (workGroup != null) {
            workGroup.shutdownGracefully().sync();
        }
    }
}
package com.chat.server;
 
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
 
public class ChatServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        //使用http的編碼器和解碼器
        pipeline.addLast(new HttpServerCodec());
        //添加塊處理器
        pipeline.addLast(new ChunkedWriteHandler());
 
        pipeline.addLast(new HttpObjectAggregator(8192));
 
        pipeline.addLast(new WebSocketServerProtocolHandler("/chat"));
        //自定義handler,處理業(yè)務(wù)邏輯
        pipeline.addLast(new ChatServerHandler());
 
 
    }
}
package com.chat.server;
 
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chat.config.ChatConfig;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
 
import java.time.LocalDateTime;
 
@Slf4j
public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        //傳過來的是json字符串
        String text = textWebSocketFrame.text();
        JSONObject jsonObject = JSON.parseObject(text);
        //獲取到發(fā)送人的用戶id
        Object msg = jsonObject.get("msg");
        String userId = (String) jsonObject.get("userId");
        Channel channel = channelHandlerContext.channel();
        if (msg == null) {
            //說明是第一次登錄上來連接,還沒有開始進行聊天,將uid加到map里面
            register(userId, channel);
        } else {
            //有消息了,開始聊天了
            sendMsg(msg, userId);
        }
 
    }
 
    /**
     * 第一次登錄進來
     *
     * @param userId
     * @param channel
     */
    private void register(String userId, Channel channel) {
        if (!ChatConfig.concurrentHashMap.containsKey(userId)) { //沒有指定的userId
            ChatConfig.concurrentHashMap.put(userId, channel);
            // 將用戶ID作為自定義屬性加入到channel中,方便隨時channel中獲取用戶ID
            AttributeKey<String> key = AttributeKey.valueOf("userId");
            channel.attr(key).setIfAbsent(userId);
        }
    }
 
    /**
     * 開發(fā)發(fā)送消息,進行聊天
     *
     * @param msg
     * @param userId
     */
    private void sendMsg(Object msg, String userId) {
        Channel channel1 = ChatConfig.concurrentHashMap.get(userId);
        if (channel1 != null) {
            channel1.writeAndFlush(new TextWebSocketFrame("服務(wù)器時間" + LocalDateTime.now() + " " + msg));
        }
    }
 
 
    /**
     * 一旦客戶端連接上來,該方法被執(zhí)行
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        log.info("handlerAdded 被調(diào)用" + ctx.channel().id().asLongText());
    }
 
    /**
     * 斷開連接,需要移除用戶
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        removeUserId(ctx);
    }
 
    /**
     * 移除用戶
     *
     * @param ctx
     */
    private void removeUserId(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        AttributeKey<String> key = AttributeKey.valueOf("userId");
        String userId = channel.attr(key).get();
        ChatConfig.concurrentHashMap.remove(userId);
        log.info("用戶下線,userId:{}", userId);
    }
 
    /**
     * 處理移除,關(guān)閉通道
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

三、存儲用戶channel 的map

package com.chat.config;
 
import io.netty.channel.Channel;
 
import java.util.concurrent.ConcurrentHashMap;
 
public class ChatConfig {
 
    public static ConcurrentHashMap<String, Channel> concurrentHashMap = new ConcurrentHashMap();
 
 
}

四、客戶端html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        var socket;
        //判斷當(dāng)前瀏覽器是否支持websocket
        if (window.WebSocket) {
            //go on
            socket = new WebSocket("ws://localhost:7000/chat");
            //相當(dāng)于channelReado, ev 收到服務(wù)器端回送的消息
            socket.onmessage = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = rt.value + "\n" + ev.data;
            }
 
            //相當(dāng)于連接開啟(感知到連接開啟)
            socket.onopen = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = "連接開啟了.."
                var userId = document.getElementById("userId").value;
                var myObj = {userId: userId};
                var myJSON = JSON.stringify(myObj);
                socket.send(myJSON)
            }
 
            //相當(dāng)于連接關(guān)閉(感知到連接關(guān)閉)
            socket.onclose = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = rt.value + "\n" + "連接關(guān)閉了.."
            }
        } else {
            alert("當(dāng)前瀏覽器不支持websocket")
        }
 
        //發(fā)送消息到服務(wù)器
        function send(message) {
            if (!window.socket) { //先判斷socket是否創(chuàng)建好
                return;
            }
            if (socket.readyState == WebSocket.OPEN) {
                //通過socket 發(fā)送消息
                var sendId = document.getElementById("sendId").value;
                var myObj = {userId: sendId, msg: message};
                var messageJson = JSON.stringify(myObj);
                socket.send(messageJson)
            } else {
                alert("連接沒有開啟");
            }
        }
    </script>
</head>
<body>
<h1 th:text="${userId}"></h1>
<input type="hidden" th:value="${userId}" id="userId">
<input type="hidden" th:value="${sendId}" id="sendId">
<form onsubmit="return false">
    <textarea name="message" style="height: 300px; width: 300px"></textarea>
    <input type="button" value="發(fā)送" onclick="send(this.form.message.value)">
    <textarea id="responseText" style="height: 300px; width: 300px"></textarea>
    <input type="button" value="清空內(nèi)容" onclick="document.getElementById('responseText').value=''">
</form>
</body>
</html>

五、controller 模擬用戶登錄以及要發(fā)送信息給誰

package com.chat.controller;
 
 
import com.chat.config.ChatConfig;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class ChatController {
 
    @GetMapping("login")
    public String login(Model model, @RequestParam("userId") String userId, @RequestParam("sendId") String sendId) {
        model.addAttribute("userId", userId);
        model.addAttribute("sendId", sendId);
        return "chat";
    }
 
    @GetMapping("sendMsg")
    public String login(@RequestParam("sendId") String sendId) throws InterruptedException {
        while (true) {
            Channel channel = ChatConfig.concurrentHashMap.get(sendId);
            if (channel != null) {
                channel.writeAndFlush(new TextWebSocketFrame("test"));
                Thread.sleep(1000);
            }
        }
 
    }
 
}

六、測試

登錄成功要發(fā)消息給bbb

登錄成功要發(fā)消息給aaa

 

到此這篇關(guān)于Java實戰(zhàn)之用springboot+netty實現(xiàn)簡單的一對一聊天的文章就介紹到這了,更多相關(guān)springboot+netty實現(xiàn)一對一聊天內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Jmeter測試必知的名詞及環(huán)境搭建

    Jmeter測試必知的名詞及環(huán)境搭建

    我們本章開始學(xué)習(xí)Jmeter,后續(xù)還會有RF以及LoadRunner 的介紹,為什么要學(xué)習(xí)Jmeter,它主要是用來做性能測試的,其中它也需要間接或直接的需要用到抓包工具
    2021-09-09
  • spring cloud eureka微服務(wù)之間的調(diào)用詳解

    spring cloud eureka微服務(wù)之間的調(diào)用詳解

    這篇文章主要介紹了spring cloud eureka微服務(wù)之間的調(diào)用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • Spring中的@ExceptionHandler異常攔截器

    Spring中的@ExceptionHandler異常攔截器

    這篇文章主要介紹了Spring中的@ExceptionHandler異常攔截器,Spring的@ExceptionHandler可以用來統(tǒng)一處理方法拋出的異常,給方法加上@ExceptionHandler注解,這個方法就會處理類中其他方法拋出的異常,需要的朋友可以參考下
    2024-01-01
  • 淺談幾種Java自定義異常處理方式

    淺談幾種Java自定義異常處理方式

    在Java中,異常是一種常見的處理機制,本文主要介紹了淺談幾種Java自定義異常處理方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 使用?mybatis?自定義日期類型轉(zhuǎn)換器的示例代碼

    使用?mybatis?自定義日期類型轉(zhuǎn)換器的示例代碼

    這篇文章主要介紹了使用?mybatis?自定義日期類型轉(zhuǎn)換器的示例代碼,這里使用mybatis中的typeHandlers?實現(xiàn)的,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • 分享幾個Java工作中實用的代碼優(yōu)化技巧

    分享幾個Java工作中實用的代碼優(yōu)化技巧

    這篇文章主要給大家分享幾個Java工作中實用代碼優(yōu)化技巧,文章基于Java的相關(guān)資料展開對其優(yōu)化技巧的分享,需要的小伙伴可以參考一下
    2022-04-04
  • Java中IO流使用FileWriter寫數(shù)據(jù)基本操作詳解

    Java中IO流使用FileWriter寫數(shù)據(jù)基本操作詳解

    這篇文章主要介紹了Java中IO流FileWriter寫數(shù)據(jù)操作,FileWriter類提供了多種寫入字符的方法,包括寫入單個字符、寫入字符數(shù)組和寫入字符串等,它還提供了一些其他的方法,如刷新緩沖區(qū)、關(guān)閉文件等,需要的朋友可以參考下
    2023-10-10
  • Java的回調(diào)機制實例詳解

    Java的回調(diào)機制實例詳解

    這篇文章主要介紹了Java的回調(diào)機制,結(jié)合實例形式詳細分析了java回調(diào)機制相關(guān)原理、用法及操作注意事項,需要的朋友可以參考下
    2019-08-08
  • 快速解決idea打開某個項目卡住的問題

    快速解決idea打開某個項目卡住的問題

    這篇文章主要介紹了解決idea打開某個項目卡住的問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Springboot mybais配置多數(shù)據(jù)源過程解析

    Springboot mybais配置多數(shù)據(jù)源過程解析

    這篇文章主要介紹了Springboot+mybais配置多數(shù)據(jù)源過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03

最新評論

临城县| 武平县| 专栏| 论坛| 黄梅县| 扎赉特旗| 蒲江县| 永登县| 新竹市| 房产| 黔江区| 武汉市| 托里县| 临夏县| 武乡县| 海南省| 德庆县| 安陆市| 巩义市| 雷州市| 浙江省| 开远市| 庆安县| 宜州市| 寻乌县| 若尔盖县| 隆尧县| 隆回县| 和田市| 扎鲁特旗| 澄迈县| 贵港市| 永胜县| 宁强县| 城步| 都昌县| 冀州市| 阜新市| 钦州市| 龙陵县| 南郑县|