Springboot整合netty实现前后端消息的推送

为什么选择Spring Boot、Netty和WebSocket?

  1. 实时性:WebSocket提供了实时的双向通信能力,适合需要实时交互的应用场景,如在线聊天、实时游戏等。
  2. 性能:Netty作为一个高性能的NIO框架,能够处理大量的并发连接,适合高流量的应用场景。
  3. 易用性:Spring Boot提供了简化的配置和启动机制,使得集成Netty和WebSocket变得更加容易。

1 添加依赖

   <!--netty的依赖-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.97.Final</version>
        </dependency>

2. 配置Netty服务器

创建一个Netty服务器类,用于启动Netty服务器并配置WebSocket处理管道。例如:

package com.example.fruit.component;

import com.example.fruit.handler.MyChannelHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
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.codec.http.websocketx.WebSocketFrameAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
public class NettyServer {

    private final int port = 9090; // 服务器端口
    public void start() throws InterruptedException {

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {

                            ch.pipeline().addLast(new HttpServerCodec());
                            ch.pipeline().addLast(new ChunkedWriteHandler());
                            ch.pipeline().addLast(new HttpObjectAggregator(65536));
                            ch.pipeline().addLast(new MyChannelHandler());
                            ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws"));
                            ch.pipeline().addLast(new WebSocketFrameAggregator(65536));

                        }
                    });
            ChannelFuture future = bootstrap.bind(port).sync();
            System.out.println("WebSocket server started at ws://localhost:" + port + "/ws");
            future.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }

    }

}

3. 配置监听的配置类

package com.example.fruit.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wb.api.utils.Alex;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/*
 *
 * 前端给服务端发送消息时调用的处理器
 *
 *
 * */
@Component
public class MyChannelHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static volatile ConcurrentHashMap<String, Channel> channels = new ConcurrentHashMap<>();

    //String message = "";

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {

        String message = textWebSocketFrame.text();

        System.out.println("Received message from client: " + message);

        //返回消息给客户端
        //broadcast(message);
        //建立是将管道添加到数组遍历
        channels.put(message, channelHandlerContext.channel());

        //System.out.println(channels.get("A") + "::::" + channels.get("B"));
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {


        //建立是将管道添加到数组遍历
        //channels.put(message, ctx.channel());
        // 当连接建立时被调用  
        System.out.println("Client connected: " + ctx.channel().remoteAddress());


    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 当连接关闭时被调用  
        System.out.println("Client disconnected: " + ctx.channel().remoteAddress());

    }


    /*发送消息给前端*/
    public static void broadcast(String message) {

        ChannelFuture channelFuture = channels.get("192.168.0.139").writeAndFlush(new TextWebSocketFrame(message));

    }


    /*发送消息给前端*/
    public static void broadcast(Alex alex, String region) {

        //判断管道存在
        if (channels.get(region) != null) {

            //转换对象为JSON
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonString = null;

            try {

                jsonString = objectMapper.writeValueAsString(alex);

            } catch (JsonProcessingException e) {

                throw new RuntimeException(e);
            }

            ChannelFuture channelFuture = channels.get(region).writeAndFlush(new TextWebSocketFrame(jsonString));
        }
        // BinaryWebSocketFrame 传递和发送音频
        // new TextWebSocketFrame(); //发送文本
    }


}
channels:管理连接的集合
broadcast:发送消息给前端的方法  
objectMapper:将发送给前端的信息 转换成JSON的对象

如何实现对连接的某个用户实现推送消息,个人理解,在中channelActive连接建立时查询一下当时登录的账号信息,然后通过键值对添加到channels进行管理。

4. 前端集成

在前端应用中,使用WebSocket API连接到服务器,并监听服务器推送的消息。例如:

const socket = new WebSocket("ws://192.168.0.139:9090/ws");
  //console.log(socket);
  socket.onopen = function(event) {
    console.log("Connected to WebSocket server");
    socket.send("Hello Server");
  };

  socket.onmessage = function(event) {
    console.log(socket);
    //const message = JSON.parse(event.data);
    // 解析JSON字符串为对象
    console.log("Received from server:", event.data);
    //alert(message);
  };

  socket.onclose = function(event) {
    console.log("Disconnected from WebSocket server");
  };

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值