基础业务模块开发
1.数据库设计,在csdn上搞定了
2.用户单表增删改查。
全局异常处理:RestControllerAdvice在类上,ExceptionHandler在方法上,里面有个value值,可以写java提供的异常以及自定义异常
3.好友:
弱好友关系,关注粉丝
强好友关系:qq,正常数据库中写一条就可以了,但是查询的时候很麻烦,所以需要写两条查询合并到一起。所以这里采用写两份的方法,A加B好友。插入from A,to B和from B ,to A ,这样查询就只需要一条语句了。
校验好友关系:1双方都添加了2from方删除3to方删除4双方删除
查询语句:先查出自己的好友列表信息,再以toid为自己的id查出对称的好友列表信息,用inner join连接起来,on条件是a.fromid=b.toid and b.fromid=a.toid。用这两份关联数据作为from条件,查出不同的状态。
select a.fromId,a.toId,(
case
when a.status =1 and b.status =1 then 1
when a.status !=1 and b.status =1 then 2
when a.status =1 and b.status !=1 then 3
when a.status !=1 and b.status !=1 then 4
end
)as status
from(select from_id as fromId,to_id as toId,if(status=1,1,0)as status from im_friendship where from_id="user1" and to_id in('user2',"user3","user4")) as a
inner join
(select from_id as fromId,to_id as toId,if(status=1,1,0)as status from im_friendship where to_id="user1" and from_id in('user2',"user3","user4")) as b
on a.fromId=b.toId and a.toId=b.fromId
不是好友的就做特殊处理,在查询之前用stream流给所有校验对象封装成一个map,然后合并这个和另一个map,不是好友的状态就返回0.
Map<String, Integer> result = req.getToIds().stream().collect(Collectors.toMap(Function.identity(), s -> 0));
//将 req.getToIds() 返回的列表元素转化为 Map 对象,其中列表元素作为键(key),对应的值(value)都设置为0。
tcp网关
1.登录与登出
用户session存在channels的map集合中作为key,channel作为值。
private static final Map<UserClientDto, NioSocketChannel> CHANNELS = new ConcurrentHashMap<>();
登录存入redis里,用map,key存不同的端pc,web,value存用户信息。同时存入channels中。
RMap<String, String> map = redissonClient.getMap(msg.getMessageHeader().getAppId() + Constants.RedisConstants.UserSessionConstants + loginPack.getUserId());
map.put(msg.getMessageHeader().getClientType()+":" + msg.getMessageHeader().getImei()
,JSONObject.toJSONString(userSession));
登出就删除session以及redis
2.心跳检测
写一个HeartBeatHandler 继承ChannelInboundHandlerAdapter,重写userEventTriggered用户自定义事件,evt转为CustomEvent,然后可以判断读写的空闲状态以实现心跳检测。
超时给用户状态改为离线。
3.rabbitmq
tcp服务调用逻辑层服务,可以使用http,rpc,mq,选择mq最大的优点是可以进行限流,
- 消息(Message):消息是 RabbitMQ 中的基本数据单元,它由消息体和消息属性组成。消息体是要传递的实际数据,而消息属性包含一些元数据,如消息的路由键、优先级等。
- 交换机(Exchange):交换机是消息的接收和分发中心。生产者将消息发布到交换机,而交换机根据指定的路由键将消息路由到一个或多个队列。
- 队列(Queue):队列是消息的存储和传递载体。消费者从队列中接收消息,并按照一定的规则进行处理。
- 绑定(Binding):绑定是交换机和队列之间的关联关系。它定义了交换机如何将消息路由到队列。
工作模式
- 简单模式(Simple Mode):也称为点对点模式(Point-to-Point),是最简单的工作模式。在简单模式中,一个生产者将消息发送到一个队列,一个消费者从该队列中接收并处理消息。每个消息只能被一个消费者消费。
- 工作队列模式(Work Queue Mode):也称为任务队列模式(Task Queue),用于在多个消费者之间共享任务。在工作队列模式中,一个生产者将消息发送到一个队列,多个消费者从该队列中竞争接收消息,并进行处理。每个消息只能被一个消费者消费。
- 发布/订阅模式(Publish/Subscribe Mode):用于将消息广播给多个消费者。在发布/订阅模式中,一个生产者将消息发送到一个交换机,交换机将消息广播给绑定到它的所有队列。每个消费者都会从自己的队列中接收消息并进行处理。
- 主题模式(Topic Mode):主题模式是发布/订阅模式的扩展,它允许消费者根据消息的主题进行选择性订阅。在主题模式中,一个生产者将消息发送到一个交换机,并指定一个主题作为消息的路由键。消费者可以使用通配符表达式来定义自己感兴趣的主题,交换机将消息根据主题进行匹配和路由。
- RPC 模式(Remote Procedure Call Mode):RPC 模式用于实现分布式系统中的远程调用。在 RPC 模式中,客户端发送请求消息到一个队列,服务端接收并处理请求,并将结果返回给客户端。客户端等待并接收服务端的响应消息。
4.注册tcp服务到zookeeper
5.服务改造
分布式netty,每个用户所在的netty可能不在一个节点上,他们之间的通讯怎么解决呢?
1.广播(发布-订阅),A给B发送消息,A去给所有节点发送一份,找到B所在的节点,完成通讯。
2.一致性hash,给每个用户session得到哈希值对应的节点,A给B发消息就可以先计算出B的节点,然后通过mq投递消息。
3.路由表,在redis中记录一张表,然后发消息的时候在这张表里查。
6.多端登录
单平台登录,2,3,多平台登录
所以登录需要 userID(用户id),appId(应用id),clientType(web,安卓,ios),imei(标识唯一的设备)。
1 只允许一端在线,手机*/电脑/web* 踢掉除了本client+imel的设备
2 允许手机*/电脑的一台设备 *+ web在线 踢掉除了本client+imel的非web*端设备*
3 允许手机和电脑单设备 + web 同时在线 踢掉非本client+imel的同端设备
4 允许所有端多设备登录 不踢任何设备文章来源:https://www.toymoban.com/news/detail-653350.html
使用redis的发布订阅模式,上线后把信息推送给所有netty服务端,接收到之后就给他根据不同的登录策略做处理。文章来源地址https://www.toymoban.com/news/detail-653350.html
到了这里,关于Netty+springboot开发即时通讯系统笔记(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!