上一篇文章Netty框架讲了Netty的理论基础,这一篇讲一下Netty在项目中的应用场景之一:消息推送功能,可以满足给所有用户推送,也可以满足给指定某一个用户推送消息,创建的是SpringBoot项目,后台服务端使用Netty技术,前端页面使用WebSocket技术。
大概实现思路:
前端使用webSocket与服务端创建连接的时候,将用户ID传给服务端
服务端将用户ID与channel关联起来存储,同时将channel放入到channel组中
如果需要给所有用户发送消息,直接执行channel组的writeAndFlush()方法
如果需要给指定用户发送消息,根据用户ID查询到对应的channel,然后执行writeAndFlush()方法
前端获取到服务端推送的消息之后,将消息内容展示到文本域中
下面是具体的代码实现,基本上每一步操作都配有注释说明,配合注释看应该还是比较容易理解的。
第零步:引入Netty的依赖,和一个工具包(只用到了json工具,可用其他json工具代替)
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.33.Final</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.2.3</version>
</dependency>
第一步:在NettyConfig中定义一个channel组,管理所有的channel,再定义一个map,管理用户与channel的对应关系。
package com.sixj.nettypush.config;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author sixiaojie
* @date 2020-03-28-15:07
*/
public class NettyConfig {
/**
* 定义一个channel组,管理所有的channel
* GlobalEventExecutor.INSTANCE 是全局的事件执行器,是一个单例
*/
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 存放用户与Chanel的对应信息,用于给指定用户发送消息
*/
private static ConcurrentHashMap<String,Channel> userChannelMap = new ConcurrentHashMap<>();
private NettyConfig() {}
/**
* 获取channel组
* @return
*/
public static ChannelGroup getChannelGroup() {
return channelGroup;
}
/**
* 获取用户channel map
* @return
*/
public static ConcurrentHashMap<String,Channel> getUserChannelMap(){
return userChannelMap;
}
}
第二步:创建NettyServer,定义两个EventLoopGroup,bossGroup辅助客户端的tcp连接请求, workGroup负责与客户端之前的读写操作,需要说明的是,需要开启一个新的线程来执行netty server,要不然会阻塞主线程,到时候就无法调用项目的其他controller接口了。
package com.sixj.nettypush.websocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
i