目录
业务描述
圈友功能的话,我们系统会将推荐的用户信息通过卡片的形式展示出来。然后由用户通过左滑不喜欢或者右滑喜欢的一种方式进行圈友的过程,也就是添加喜欢用户的一种操作。
如果双方都彼此喜欢的话,就会成为好友。
技术描述
1.圈友推荐
首先的话,是我们在推荐用户这一块,前端通过Get方法直接从后端获取数据并返回;在进行随机用户推荐的时候,我们会先从当前用户的喜欢表userlike从中获取用户已经喜欢或者不喜欢的用户用于筛选;随机推荐的时候就会排除这些当前用户已经喜欢或者不喜欢的数据,然后在剩下的用户中随机推送10条用户的数据,如果数据不存在的话,会构造默认数据进行推荐,然后通过小卡片的形式展示出来。
在进行随机推送的时候,会使用到mongoDB的一个统计函数,随机获取用户列表。通过使用mongoDB中的聚合函数aggregate,主要用于处理数据,如统计平均值,求和等等,并返回计算后的结果;
// 圈友功能推荐,卡片展示
//构造查询推荐用户,其条件不能包含上面以及喜欢或者不喜欢的用户
@Override
public List<RecommendUser> getCardsList(Long userId,int i) {
//获取当前用户喜欢和不喜欢的列表
List<UserLike> list = mongoTemplate.find(Query.query(Criteria.where("userId").is(userId)), UserLike.class);
List<Long> ids = CollUtil.getFieldValues(list, "likeUserId", Long.class);
//根据id查询,并排除以及喜欢或者不喜欢的用户,关键字nin 排除
//查询当前用户推荐的所有toUserId=当前登录用户
Criteria criteria = Criteria.where("toUserId").is(userId);
//排除userId用户
criteria.and("userId").nin(ids);
//使用统计函数,随机获取推荐的用户列表
TypedAggregation<RecommendUser> newAggregation = TypedAggregation.newAggregation(RecommendUser.class,
Aggregation.match(criteria), //指定查询的条件
Aggregation.sample(i));//指定推荐的数量
AggregationResults<RecommendUser> results = mongoTemplate.aggregate(newAggregation, RecommendUser.class);
//构造返回需要的列表
return results.getMappedResults();
}
2.左滑右滑,redis缓存
然后就是用户的操作,左滑不喜欢,右滑喜欢;这里会出现涉及到两种表,一个是用户的喜欢表userLike和用户的好友关系表Friend。
我们将用户的喜欢与不喜欢列表保存在redis中,通过固定喜欢前缀或不喜欢前缀+用户id的形式采用set的数据类型保存在redis中。左滑不喜欢/右滑喜欢,会调用喜欢或者不喜欢的接口,然后去查询该用户是否已经喜欢或者不喜欢对方(通过用户id和对方的Id为条件查询userLike表看数据是否存在),如果没有就保存,有就更新。
返回一个布尔值判断此操作是否成功。
对返回的布尔值进行判断,如果是true的话则操作redis写入喜欢或者不喜欢的数据。
如果是喜欢,会先删除redis中标记的不喜欢该用户的信息,然后在添加该用户的信息;通过USER_NOT_LIKE的固定前缀+当前用户的id为key,喜欢对方的id为value
通过redisTemplate.opsForSet().remove(key,value)进行查询并删除。
然后使用USER__LIKE为前缀相同的用户id和喜欢对方的id为key和value
通过redisTemplate.opsForSet().add(key,value)进行保存。
反之如果是不喜欢,就删除标记喜欢的数据,添加不喜欢的数据。
// UserHolder.getUserId() 通过令牌拦截器的方法获取当前登录的id
// likeUserId 用户喜欢的用户id
//2、操作redis,写入喜欢的数据,删除不喜欢的数据
redisTemplate.opsForSet().remove("USER_NOT_LIKE"+UserHolder.getUserId(),likeUserId.toString());
redisTemplate.opsForSet().add("USER__LIKE"+UserHolder.getUserId(),likeUserId.toString());
//2、操作redis,写入不喜欢的数据,删除喜欢的数据
redisTemplate.opsForSet().add("USER_NOT_LIKE"+UserHolder.getUserId(),likeUserId.toString());
redisTemplate.opsForSet().remove("USER_LIKE"+UserHolder.getUserId(),likeUserId.toString());
如果是false就直接报错。
这里我们定了一个自定义异常,异常类继承了RuntimeException接口;还自定义了一个统一异常处理类,使用@ControllerAdivice注解声明这个一个异常处理类,使用在方法上编写注解@ExceptionHanlder指定此方法可以处理的异常类型。其中会涉及到的ErrorResult是我们自定义的一个异常vo对象,构造响应数据。
3. 双向喜欢
判断完成之后,统一的还需要判断是否双向喜欢,如果是双向喜欢则就互相成为好友。使用redis中set数据类型中的isMember()方法进行判断,可以在redis进行判断传入的两个值是否互相双向标记。
将喜欢的用户id为key,当前用户id为value,使用isMember()方法进行判断,返回true说明双向喜欢,false则互相不喜欢。
//判断是否双向喜欢
public Boolean isLike(Long likeUserId, Long userId){
//将喜欢人的id做key进行查找自己的id
String key = Constants.USER_LIKE_KEY + likeUserId;
return redisTemplate.opsForSet().isMember(key,userId.toString());
}
对返回值进行判断,如果为true说明是双向喜欢的,进行互相添加好友;不仅仅要在mongodb数据库中好友关系表添加两条数据,你的好友是我,我的好友是你;还有通过设置环信账号,在环信上彼此添加为好友;因为只有环信互为好友才能进行即时通信。即需要数据库表添加好友关系,环信账号添加好友关系。
表数据
UserLike 用户喜欢表
用户喜欢表userLike;表中友用户自己的id,喜欢或者不喜欢对方用户的id,还有一个字段isLike是一个布尔值,用来判断是否喜欢,true就是喜欢,false就是不喜欢。还有就是创建时间和更新时间字段。
Friend 好友关系表
主要是记录保存用户和朋友之间的好友关系。有用户id和朋友id,其次还有一个创建时间。如果双方是好友的话,就会一次性保存两条数据,你是我的好友,我是你的好友。