java netty post_API调用Netty长链接执行发送消息(在线数、用户列表)

前言

在原项目中,对于WebSocket的长连接,聊天系统并没有开放接口出来给第三方的系统调用,只有我们系统内部的人员才知道,确切的说系统内部也没有实际的查询接口,那么我们今天就来实现这个功能。

在Netty下的Websocket长连接中,以API形式获取在线用户数,与在线用户列表,并针对某个用户已API调用的形式进行数据发送,而不需要所谓的前端页面去创建websocket连接。

实践流程

存放Channel的容器

首先,我们需要一个类似ChannelGroup的连接池来存放我们的连接实例,这里我直接在原来本地模拟的一个LikeRedisTemplate中新建了一个ConcurrentHashMap,用于存放对应的用户名——连接实例的键值对。

方便后期API调用时可以通过这个LikeRedisTemplate中的这个Map进行获取、删除及相关信息。

/**存放链接池实例*/

private Map ChannelRedisMap = new ConcurrentHashMap<>();

/**

* 存储对应的用户名与Netty链接实例

* @param name 登录用户名

* @param channel Netty链接实例

*/

public void saveChannel(Object name,Object channel){

ChannelRedisMap.put(name,channel);

}

/**

* 获取存储池中的链接实例

* @param name 登录用户名

* @return {@link io.netty.channel.Channel 链接实例}

*/

public Object getChannel(Object name){

return ChannelRedisMap.get(name);

}

/**

* 删除存储池实例

* @param name 登录用户名

*/

public void deleteChannel(Object name){

ChannelRedisMap.remove(name);

}

/**

* 获取储存池链接数

* @return 在线数

*/

public Integer getSize(){

return ChannelRedisMap.size();

}

/**

* 返回在线用户列表信息

* @return 用户名列表

*/

public Object getOnline() {

List result = new ArrayList<>();

for (Object key:ChannelRedisMap.keySet()){

result.add(key);

}

return result;

}

Handler中执行存储操作

有了容器,我们就需要在对应的位置进行连接实例的键值对存储,我目前选择了在聊天消息传输过程中进行存储,暂时还没有抽象出来。

并在连接断开时也要做相关的处理。

//用户登录判断

if (redisTemplate.check(incoming.id(),rName)){

//临时存储聊天数据

cacheTemplate.save(rName,rMsg);

//存储随机链接ID与对应登录用户名

redisTemplate.save(incoming.id(),rName);

//存储登录用户名与链接实例,方便API调用链接实例

redisTemplate.saveChannel(rName,incoming);

}else{

incoming.writeAndFlush(new TextWebSocketFrame("存在二次登陆,系统已为你自动断开本次链接"));

channels.remove(ctx.channel());

ctx.close();

return;

}

@Override

public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

//删除存储池对应实例

String name = (String) redisTemplate.getName(ctx.channel().id());

redisTemplate.deleteChannel(name);

//删除默认存储对应关系

redisTemplate.delete(ctx.channel().id());

channels.remove(ctx.channel());

}

发送方法

我直接在SendUtil中写一个系统发送的方法,输出也是转为TextWebSocketFrame

/**

* 想指定链接发送数据

* @param msg 消息

* @param channel 指定链接

* @return {@link String}

*/

public static String sendTest(String msg,Channel channel) {

try {

channel.writeAndFlush(new TextWebSocketFrame( "[系统API]" + msg));

return "success";

}catch (Exception e){

e.printStackTrace();

return "error";

}

}

定义API

这个就简单一些了,定义一个统一返回的Bean,还有API的返回工具类,然后写对应的API接口方法。

@RestController

@RequestMapping("/back")

public class NCBackController {

@Autowired

private LikeRedisTemplate redisTemplate;

/**

* 获取在线用户数

* @return {@link ResultVo}

*/

@GetMapping("/size")

public ResultVo getSize(){

return ResultVOUtil.success(redisTemplate.getSize());

}

/**

* 获取在线用户列表

* @return {@link ResultVo}

*/

@GetMapping("/online")

public ResultVo getOnline(){

return ResultVOUtil.success(redisTemplate.getOnline());

}

/**

* API调用向在线用户发送消息

* @param name 用户名

* @param msg 消息

* @return {@link ResultVo}

*/

@PostMapping("/send")

public ResultVo send(@RequestParam String name,@RequestParam String msg){

Channel channel = (Channel) redisTemplate.getChannel(name);

if (channel == null){

return ResultVOUtil.error(555,"当前用户连接已断开");

}

String result = SendUtil.sendTest(msg,channel);

return ResultVOUtil.success(result);

}

}

效果

我在项目中添加Swagger方便查看与简单测试API,引入对应pom,在启动类加一个注解即可。

启动项目后登陆界面,发送了一个基本消息。

5a76e5b18608225a657f0117482dd753.png

Swagger这边的页面打开后,测试几个API,都是成功的。

2ef82d02db98dcb05e4a1db2fa7f3987.png

d8415b1a1a7064e35c11e0a0380e062c.png

f1e2055c667f103aa1b00e53d6e191cd.png

06ce897794526357142bf4dd1afa20d0.png

好了,结尾还是成功的,不过作为一个好产品是不能仅仅这样的,后续我们继续完善。

本项目是本人近期GitHub的核心发展项目,有兴趣的朋友可以去了解下

GitHub

项目名:InChat

项目地址:https://github.com/UncleCatMy...

项目介绍:基于Netty4与SpringBoot,聊天室WebSocket(文字图片)、Iot物联网-MQTT协议、TCP/IP协议单片机通信,异步存储聊天数据

如果本文对你有所帮助,欢迎关注个人技术公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值