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。
用户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
写一个HeartBeatHandler 继承ChannelInboundHandlerAdapter,重写userEventTriggered用户自定义事件,evt转为CustomEvent,然后可以判断读写的空闲状态以实现心跳检测。
超时给用户状态改为离线。
tcp服务调用逻辑层服务,可以使用http,rpc,mq,选择mq最大的优点是可以进行限流,
工作模式
分布式netty,每个用户所在的netty可能不在一个节点上,他们之间的通讯怎么解决呢?
1.广播(发布-订阅),A给B发送消息,A去给所有节点发送一份,找到B所在的节点,完成通讯。
2.一致性hash,给每个用户session得到哈希值对应的节点,A给B发消息就可以先计算出B的节点,然后通过mq投递消息。
3.路由表,在redis中记录一张表,然后发消息的时候在这张表里查。
单平台登录,2,3,多平台登录
所以登录需要 userID(用户id),appId(应用id),clientType(web,安卓,ios),imei(标识唯一的设备)。
1 只允许一端在线,手机*/电脑/web* 踢掉除了本client+imel的设备
2 允许手机*/电脑的一台设备 *+ web在线 踢掉除了本client+imel的非web*端设备*
3 允许手机和电脑单设备 + web 同时在线 踢掉非本client+imel的同端设备
4 允许所有端多设备登录 不踢任何设备
使用redis的发布订阅模式,上线后把信息推送给所有netty服务端,接收到之后就给他根据不同的登录策略做处理。