使用Springboot + netty 打造聊天服务(一)

目录

1、创建Springboot工程

在Idea里创建Springboot工程,Language选择Java,Type选择Maven,Project SDK 选择Java8。

1.1、项目创建

成功创建项目,Sringboot版本 2.7.6,Java版本8。

1.2、环境配置

检查Maven配置,主要检查settings.xml和本地Maven仓库

1.2.1、检查settings.xml

在settings.xml里配置上阿里云镜像

xml 复制代码
  <mirrors>
      <mirror>
        <id>alimaven</id>
        <mirrorOf>central</mirrorOf>
        <name>aliyun maven</name>
        <url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
      </mirror>
  </mirrors>

1.2.2、检查本地仓库

Maven版本3.6.3,在Maven文件夹下创建了res文件夹,做为Java工程的Maven本地仓库地址,此文件通常都在500MB以上,随着本地项目数而递增。

1.3、项目结构配置

打开【Project Structure】

1.3.1、配置JDK

修改SDK、Language level等配置。

1.4、添加依赖

上述操作都是打基础,搭架子和配置环境,下一步我们需要加载netty 的相关依赖包。

在 pom.xml 文件中添加 Netty 和 Spring Boot 相关的依赖:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.68.Final</version> <!-- 请根据需要选择合适的版本 -->
    </dependency>
</dependencies>

2、构造NettyWebsocketServer

2.1、创建一个 Netty 服务器配置类

java 复制代码
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import org.springframework.context.annotation.Configuration;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.bootstrap.ServerBootstrap;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import io.netty.channel.*;

@Slf4j
@Configuration
public class NettyWebsocketServer {

    //bossGroup 连接线程组,主要负责接受客户端连接
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    private EventLoopGroup workerGroup = new NioEventLoopGroup();
    private ChannelFuture channelFuture;

    @PostConstruct
    public void start() throws InterruptedException {
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            // 因为使用 HTTP 协议,所以需要 HTTP编码器,解码器
                            pipeline.addLast(new HttpServerCodec());
                            // 以块方式,添加 chunkedWriter 处理器
                            pipeline.addLast(new ChunkedWriteHandler());
                            /**
                             * 1. http数据在传输中是分段的,HttpObjectAggregator 可以把多个段聚合起来
                             * 2. 这就是为什么当浏览器发送大量数据时,就会发出多次 http请求的原因
                             */
                            pipeline.addLast(new HttpObjectAggregator(8192));
                            // 保存用户ip
                            // pipeline.addLast(new HttpHeadersHandler());
                            pipeline.addLast(new WebSocketServerProtocolHandler("/chat"));

                            pipeline.addLast(new IdleStateHandler(60, 5, 0));
                            pipeline.addLast(new ChatHandler());  //添加自定义handler
                        }
                    });

            // Bind and start to accept incoming connections.
            channelFuture = b.bind(9091).sync();
            if(channelFuture.isSuccess()) {
                log.info("netty启动成功");
            }
            // 对通道关闭进行监听
            channelFuture.channel().closeFuture().sync();
        } finally {
            if (channelFuture != null && channelFuture.isSuccess()) {
                System.out.println("Netty server started on port 9091");
            } else {
                System.err.println("Netty server failed to start");
            }
        }
    }
}

2.2、添加自定义handler

创建一个自定义的 ChannelHandler 来处理客户端的请求:

java 复制代码
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ChatHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 处理收到的消息
        System.out.println("Received message: " + msg);
        ctx.writeAndFlush("Message received: " + msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

3、使用ApiFox调试

3.1、启动服务

3.2、添加Apifox WebSocket接口

输入ws接口地址,成功连接上netty服务

3.3、客户端发送数据

3.4、Debug调试数据

这里可以看到已经接收到数据了。

我们在Debug数据时,可以看到msg的data类型

TextWebSocketFrame(data: PooledUnsafeDirectByteBuf(ridx: 0, widx: 61, cap: 61))

3.5、客户端结果

客户端收不到服务端回复的消息。

3.6、改造服务端代码

查看数据结果

4、总结

在文章里,我们实现了Springboot 集成netty,并使用apiFox客户端发送了消息到netty服务,最终客户端收到服务端的应答。

下一章节,我们讲解解码器的使用,使得我们的数据可以可视化,以及正常的展示。

相关推荐
言、雲2 分钟前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇8 分钟前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
Yvemil737 分钟前
《开启微服务之旅:Spring Boot 从入门到实践》(三)
java
Anna。。39 分钟前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
计算机学长felix1 小时前
基于SpringBoot的“交流互动系统”的设计与实现(源码+数据库+文档+PPT)
spring boot·毕业设计
.生产的驴1 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
爱上语文1 小时前
宠物管理系统:Dao层
java·开发语言·宠物
顽疲1 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端
机器之心1 小时前
AAAI 2025|时间序列演进也是种扩散过程?基于移动自回归的时序扩散预测模型
人工智能·后端
王ASC2 小时前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web