课程总结
1.圈子动态查询
-
好友动态与推荐动态
-
掌握动态的表关系
-
掌握推荐动态的流程和代码实现
2.圈子互动
-
使用Redis和冗余字段优化查询效率
-
发布评论
-
点赞与取消点赞
-
喜欢与取消喜欢
一. 动态查询
1.1 具体内容
执行流程
我的动态:查询个人发布的动态列表(分页查询),和之前实现的好友动态,推荐动态实现逻辑是一致。
1.2 需求分析
动态查询包含三个部分
-
个人动态(已实现)
-
好友动态
- 操作用户查看所有好友发布的动态内容
-
推荐动态
- 探花交友平台接入大数据系统,根据个人喜欢实时计算出感兴趣的动态内容
1.3 查询好友动态
查询好友动态与查询推荐动态显示的结构是一样的,只是其查询数据源不同
1. 接口文档
API接口文档:http://192.168.136.160:3000/project/19/interface/api/142
2. 表结构
3. 代码步骤
-
Controller层接受请求参数
-
Service数据封装
- 调用API查询好友动态详情数据
- 调用API查询动态发布人详情
- 构造VO对象
-
API层根据用户ID查询好友发布动态详情
- 查询好友时间线表
- 查询动态详情
4. 代码实现
MovementController
//查询好友动态
@GetMapping
public ResponseEntity movements(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findFriendMovements(page,pagesize);
return ResponseEntity.ok(pr);
}
MovementService
//好友动态
public PageResult findFriendMovements(Integer page, Integer pagesize) {
//1、获取当前用户id
Long userId = UserHolder.getUserId();
//2、查询数据列表
List<Movement> items = movementApi.findFriendMovements(userId,page,pagesize);
//3、非空判断
if(CollUtil.isEmpty(items)) {
return new PageResult();
}
//4、获取好友用户id
List<Long> userIds = CollUtil.getFieldValues(items, "userId", Long.class);
//5、循环数据列表
Map<Long, UserInfo> userMaps = userInfoApi.findByIds(userIds, null);
List<MovementsVo> vos = new ArrayList<>();
for (Movement item : items) {
//5、一个Movement构建一个Vo对象
UserInfo userInfo = userMaps.get(item.getUserId());
MovementsVo vo = MovementsVo.init(userInfo, item);
vos.add(vo);
}
//6、构建返回值
return new PageResult(page,pagesize,0L,vos);
}
movementApi
@Override
public List<Movement> findFriendMovements(Long friendId, Integer page, Integer pagesize) {
//1、查询好友时间线表
Query query = Query.query(Criteria.where("friendId").is(friendId))
.skip((page - 1)*pagesize).limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
List<MovementTimeLine> lines = mongoTemplate.find(query, MovementTimeLine.class);
//2、提取动态id集合
List<ObjectId> movementIds = CollUtil.getFieldValues(lines, "movementId", ObjectId.class);
//3、根据动态id查询动态详情
Query movementQuery = Query.query(Criteria.where("id").in(movementIds));
return mongoTemplate.find(movementQuery, Movement.class);
}
1.4 查询推荐动态(redis,stream)
1. redis数据格式
推荐动态是通过推荐系统计算出的结果,现在我们只需要实现查询即可,推荐系统在后面的课程中完成。
推荐系统计算完成后,会将结果数据写入到Redis中,数据如下:
192.168.31.81:6379> get MOVEMENTS_RECOMMEND_1
"2562,3639,2063,3448,2128,2597,2893,2333,3330,2642,2541,3002,3561,3649,2384,2504,3397,2843,2341,2249"
可以看到,在Redis中的数据是有多个发布id组成(pid)由逗号分隔。所以实现中需要自己对这些数据做分页处理。
- 推荐动态数据格式
推荐动态数据存入Redis服务器中
存入的数据KEY为MOVEMENTS_RECOMMED_{用户id}
存入的数据VALUE为:动态PID字符串(多个PID间使用“,”连接)
2. 接口文档
API接口文档:http://192.168.136.160:3000/project/19/interface/api/145
3. 思路分析
Redis中存储的是动态详情表的唯一数字标识 pid字段
当不存在推荐数据时,需要构造默认数据返回
4. 代码步骤
-
Controller层接受请求参数
-
Service数据封装
- 从redis获取当前用户的推荐PID列表
- 如果不存在,调用API随机获取10条动态数据
- 如果存在,调用API根据PID列表查询动态数据
- 构造VO对象
-
API层编写方法
- 随机获取
- 根据pid列表查询
5. 代码实现
Constants枚举类
package com.tanhua.commons.utils;
//常量定义
public class Constants {
//手机APP短信验证码CHECK_CODE_
public static final String SMS_CODE = "CHECK_CODE_";
//推荐动态
public static final String MOVEMENTS_RECOMMEND = "MOVEMENTS_RECOMMEND_";
//推荐视频
public static final String VIDEOS_RECOMMEND = "VIDEOS_RECOMMEND_";
//圈子互动KEY
public static final String MOVEMENTS_INTERACT_KEY = "MOVEMENTS_INTERACT_";
//动态点赞用户HashKey
public static final String MOVEMENT_LIKE_HASHKEY = "MOVEMENT_LIKE_";
//动态喜欢用户HashKey
public static final String MOVEMENT_LOVE_HASHKEY = "MOVEMENT_LOVE_";
//视频点赞用户HashKey
public static final String VIDEO_LIKE_HASHKEY = "VIDEO_LIKE";
//访问用户
public static final String VISITORS = "VISITORS";
//关注用户
public static final String FOCUS_USER = "FOCUS_USER_{}_{}";
//初始化密码
public static final String INIT_PASSWORD = "123456";
//环信用户前缀
public static final String HX_USER_PREFIX = "hx";
//jwt加密盐
public static final String JWT_SECRET = "itcast";
//jwt超时时间
public static final int JWT_TIME_OUT = 3_600;
}
MovementController
/**
* 推荐动态
*/
@GetMapping("/recommend")
public ResponseEntity recommend(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findRecommendMovements(page,pagesize);
return ResponseEntity.ok(pr);
}
MovementService
//查询推荐动态
public PageResult findRecommendMovements(Integer page, Integer pagesize) {
//1、从redis中获取推荐数据
String redisKey = Constants.MOVEMENTS_RECOMMEND +UserHolder.getUserId();
String redisValue = redisTemplate.opsForValue().get(redisKey);
//2、判断推荐数据是否存在
List<Movement> list = Collections.EMPTY_LIST;
if(StringUtils.isEmpty(redisValue)) {
//3、如果不存在,调用API随机构造10条动态数据
list = movementApi.randomMovements(pagesize);
}else {
//4、如果存在,处理pid数据 "16,17,18,19,20,21,10015,10020,10040,10064,10092,10093,10099,10067" 15
String[] values = redisValue.split(",");
//判断当前页的起始条数是否小于数组总数
if