springboot集成netty实现websocket

bash 复制代码
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.50.Final</version>
        </dependency>
复制代码
@SpringBootApplication
public class RouteDefenseApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(RouteDefenseApplication.class, args);
        System.out.println("启动成功!");
    }

    @Autowired
    private NettyServer nettyServer;

    @Override
    public void run(String... args) throws Exception {
        new Thread(nettyServer).start();
    }
}
bash 复制代码
@Component
public class NettyServer implements Runnable{

    public void start(InetSocketAddress address) {
     EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.option(ChannelOption.SO_BACKLOG, 1024);
            sb.group(group, bossGroup) // 绑定线程池
            .channel(NioServerSocketChannel.class) // 指定使用的channel
                    .localAddress(address)// 绑定监听端口
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                        //websocket协议本身是基于http协议的,所以这边也要使用http解编码器
                            ch.pipeline().addLast(new HttpServerCodec());
                            //以块的方式来写的处理器
                            ch.pipeline().addLast(new ChunkedWriteHandler());
                            ch.pipeline().addLast(new HttpObjectAggregator(8192));
                             ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", "WebSocket", true, 65536 * 10));
                            ch.pipeline().addLast(new MyWebSocketHandler());//自定义消息处理类
                        }
                    });
                    ChannelFuture cf = sb.bind(address).sync(); // 服务器异步创建绑定
            System.out.println(NettyServer.class + "已启动,正在监听: " + cf.channel().localAddress());
            cf.channel().closeFuture().sync(); // 关闭服务器通道
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
        try {
                group.shutdownGracefully().sync(); // 释放线程池资源
                bossGroup.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            }
    }

    @Override
    public void run() {
        InetSocketAddress address = new InetSocketAddress(10007);
        this.start(address);
    }
}
bash 复制代码
public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("与客户端建立连接,通道开启!");
        //添加到channelGroup通道组
        MyChannelHandlerPool.channelGroup.add(ctx.channel());
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("与客户端断开连接,通道关闭!");
        //从channelGroup通道组删除
        MyChannelHandlerPool.channelGroup.remove(ctx.channel());
    }
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        //接收的消息
        System.out.println(String.format("收到客户端%s的数据:%s" ,ctx.channel().id(), msg.text()));

        // 单独发消息
        // sendMessage(ctx);
        // 群发消息
        sendAllMessage();
    }
    private void sendMessage(ChannelHandlerContext ctx){
        String message = "消息";
        ctx.writeAndFlush(new TextWebSocketFrame(message));
    }

    private void sendAllMessage(){
        String message = "我是服务器,这是群发消息";
        MyChannelHandlerPool.channelGroup.writeAndFlush(new TextWebSocketFrame(message));
    }

}
bash 复制代码
public class MyChannelHandlerPool {
    public MyChannelHandlerPool() {
    }

    //可以存储userId与ChannelId的映射表
    public static ConcurrentHashMap<String, ChannelId> channelIdMap = new ConcurrentHashMap<>();

    //channelGroup通道组
    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}

发送消息:

bash 复制代码
MyChannelHandlerPool.channelGroup.writeAndFlush("我是后端消息!!!!!");
相关推荐
毕设源码-郭学长1 分钟前
【开题答辩全过程】以 基于springboot的健身房信息管理为例,包含答辩的问题和答案
java·spring boot·后端
爱编码的傅同学8 分钟前
【单例模式】深入理解懒汉与饿汉模式
java·javascript·单例模式
better_liang11 分钟前
每日Java面试场景题知识点之-ThreadLocal在Web项目中的实战应用
java· threadlocal· web开发· 多线程· 企业级开发
Rysxt_21 分钟前
Spring Boot 4.0 新特性深度解析与实战教程
java·spring boot·后端
Wang153044 分钟前
Java集合框架
java
梦想的旅途21 小时前
企业微信外部群消息推送实战指南
java·golang·企业微信
独自破碎E1 小时前
怎么实现一个滑动验证码功能?又如何防止被机器识别破解
java·spring boot·后端
lbb 小魔仙1 小时前
【Java】Spring Data JPA 详解:ORM 映射、查询方法与复杂 SQL 处理
java·开发语言·sql·spring cloud
倚肆1 小时前
Kafka部署指南:单机开发模式与集群生产模式( 4.1.1 版本)
java·分布式·kafka
qq13267029402 小时前
ARM版统信UOS桌面安装JDK
java·jdk·arm·统信uos·毕昇jdk 11