【探花交友】day05—圈子互动(上)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 【探花交友】day05—圈子互动

课程说明

  • 圈子动态查询
  • 圈子实现评论
  • 圈子实现点赞、喜欢功能
  • 圈子实现评论

1、动态查询

我的动态:查询个人发布的动态列表(分页查询),和之前实现的好友动态,推荐动态实现逻辑是一致。

1.1、查询好友动态

查询好友动态与查询推荐动态显示的结构是一样的,只是其查询数据源不同

1.1.1、接口文档

API接口文档:http://192.168.136.160:3000/project/19/interface/api/142

1.1.2、代码步骤

  • Controller层接受请求参数
  • Service数据封装
  • 调用API查询好友动态详情数据
  • 调用API查询动态发布人详情
  • 构造VO对象
  • API层根据用户ID查询好友发布动态详情
  • 查询好友时间线表
  • 查询动态详情

1.1.3、代码实现

MovementController

1. /**
2.      * 查询好友动态
3.      */
4. @GetMapping
5. public ResponseEntity movements(@RequestParam(defaultValue = "1") Integer page,
6. @RequestParam(defaultValue = "10") Integer pagesize) {
7. PageResult pr = movementService.findFriendMovements(page,pagesize);
8. return ResponseEntity.ok(pr);
9.     }

MovementService

1. //好友动态
2. public PageResult findFriendMovements(Integer page, Integer pagesize) {
3. //1、获取当前用户id
4. Long userId = UserHolder.getUserId();
5. //2、查询数据列表
6.     List<Movement> items = movementApi.findFriendMovements(userId,page,pagesize);
7. //3、非空判断
8. if(CollUtil.isEmpty(items)) {
9. return new PageResult();
10.     }
11. //4、获取好友用户id
12.     List<Long> userIds = CollUtil.getFieldValues(items, "userId", Long.class);
13. //5、循环数据列表
14.     Map<Long, UserInfo> userMaps = userInfoApi.findByIds(userIds, null);
15.     List<MovementsVo> vos = new ArrayList<>();
16. for (Movement item : items) {
17. //5、一个Movement构建一个Vo对象
18. UserInfo userInfo = userMaps.get(item.getUserId());
19. MovementsVo vo = MovementsVo.init(userInfo, item);
20.         vos.add(vo);
21.     }
22. //6、构建返回值
23. return new PageResult(page,pagesize,0L,vos);
24. }

movementApi

1. @Override
2. public List<Movement> findFriendMovements(Long friendId, Integer page, Integer pagesize) {
3. //1、查询好友时间线表
4. Query query = Query.query(Criteria.where("friendId").in(friendId))
5.             .skip((page - 1)*pagesize).limit(pagesize)
6.             .with(Sort.by(Sort.Order.desc("created")));
7.     List<MovementTimeLine> lines = mongoTemplate.find(query, MovementTimeLine.class);
8. //2、提取动态id集合
9.     List<ObjectId> movementIds = CollUtil.getFieldValues(lines, "movementId", ObjectId.class);
10. //3、根据动态id查询动态详情
11. Query movementQuery = Query.query(Criteria.where("id").in(movementIds));
12. return mongoTemplate.find(movementQuery, Movement.class);
13. }

1.2、查询推荐动态

推荐动态是通过推荐系统计算出的结果,现在我们只需要实现查询即可,推荐系统在后面的课程中完成。

推荐系统计算完成后,会将结果数据写入到Redis中,数据如下:

1. 192.168.31.81:6379> get MOVEMENTS_RECOMMEND_1
2. "2562,3639,2063,3448,2128,2597,2893,2333,3330,2642,2541,3002,3561,3649,2384,2504,3397,2843,2341,2249"

可以看到,在Redis中的数据是有多个发布id组成(pid)由逗号分隔。所以实现中需要自己对这些数据做分页处理。

1.2.1、接口文档

API接口文档:http://192.168.136.160:3000/project/19/interface/api/145

1.2.2、代码步骤

  • Controller层接受请求参数
  • Service数据封装
  • 从redis获取当前用户的推荐PID列表
  • 如果不存在,调用API随机获取10条动态数据
  • 如果存在,调用API根据PID列表查询动态数据
  • 构造VO对象
  • API层编写方法
  • 随机获取
  • 根据pid列表查询

1.2.3、代码实现

Constants

1. package com.tanhua.commons.utils;
2. 
3. //常量定义
4. public class Constants {
5. 
6. //手机APP短信验证码CHECK_CODE_
7. public static final String SMS_CODE = "CHECK_CODE_";
8. 
9.  //推荐动态
10.   public static final String MOVEMENTS_RECOMMEND = "MOVEMENTS_RECOMMEND_";
11. 
12. //推荐视频
13. public static final String VIDEOS_RECOMMEND = "VIDEOS_RECOMMEND_";
14. 
15.   //圈子互动KEY
16.   public static final String MOVEMENTS_INTERACT_KEY = "MOVEMENTS_INTERACT_";
17. 
18. //动态点赞用户HashKey
19. public static final String MOVEMENT_LIKE_HASHKEY = "MOVEMENT_LIKE_";
20. 
21. //动态喜欢用户HashKey
22. public static final String MOVEMENT_LOVE_HASHKEY = "MOVEMENT_LOVE_";
23. 
24. //视频点赞用户HashKey
25. public static final String VIDEO_LIKE_HASHKEY = "VIDEO_LIKE";
26. 
27. //访问用户
28. public static final String VISITORS = "VISITORS";
29. 
30. //关注用户
31. public static final String FOCUS_USER = "FOCUS_USER_{}_{}";
32. 
33.   //初始化密码
34. public static final String INIT_PASSWORD = "123456";
35. 
36. //环信用户前缀
37. public static final String HX_USER_PREFIX = "hx";
38. 
39. //jwt加密盐
40. public static final String JWT_SECRET = "itcast";
41. 
42. //jwt超时时间
43. public static final int JWT_TIME_OUT = 3_600;
44. }

MovementController

1. /**
2.  * 推荐动态
3.  */
4. @GetMapping("/recommend")
5. public ResponseEntity recommend(@RequestParam(defaultValue = "1") Integer page,
6. @RequestParam(defaultValue = "10") Integer pagesize) {
7. PageResult pr = movementService.findRecommendMovements(page,pagesize);
8. return ResponseEntity.ok(pr);
9. }

MovementService

1. //推荐动态
2. public PageResult findRecommendMovements(Integer page, Integer pagesize) {
3. String redisKey = "MOVEMENTS_RECOMMEND_" + UserHolder.getUserId();
4. String redisData = this.redisTemplate.opsForValue().get(redisKey);
5.     List<Movement> list = Collections.EMPTY_LIST;
6. if(StringUtils.isEmpty(redisData)){
7.         list = movementApi.randomMovements(pagesize);
8.     }else {
9.         String[] split = redisData.split(",");
10. if ((page-1) * pagesize > split.length) {
11. return new PageResult();
12.         }
13.         List<Long> pids = Arrays.stream(split)
14.                 .skip((page - 1) * pagesize)
15.                 .limit(pagesize)
16.                 .map(e -> Convert.toLong(e))
17.                 .collect(Collectors.toList());
18.         list = movementApi.findByPids(pids);
19.     }
20.     List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
21. //5、循环数据列表
22.     Map<Long, UserInfo> userMaps = userInfoApi.findByIds(userIds, null);
23.     List<MovementsVo> vos = new ArrayList<>();
24. for (Movement item : list) {
25. //5、一个Movement构建一个Vo对象
26. UserInfo userInfo = userMaps.get(item.getUserId());
27. MovementsVo vo = MovementsVo.init(userInfo, item);
28.         vos.add(vo);
29.     }
30. //6、构建返回值
31. return new PageResult(page,pagesize,0L,vos);
32. }

movementApi

1. //随机获取
2. public List<Movement> randomMovements(Integer counts) {
3. 
4. TypedAggregation aggregation = Aggregation.newAggregation(Movement.class,
5.             Aggregation.sample(counts));
6. 
7.     AggregationResults<Movement> movements = mongoTemplate.aggregate(aggregation,Movement.class);
8. 
9. return movements.getMappedResults();
10. }
11. 
12. 
13. //根据PID查询
14. public List<Movement> findByPids(List<Long> pids) {
15. Query query = Query.query(Criteria.where("pId").in(pids));
16. return mongoTemplate.find(query, Movement.class);
17. }

1.3、根据id查询动态

根据id查询动态:当手机端查看评论内容时(需要根据动态id,查询动态详情),后续再去查询评论列表

1.3.1、接口文档

API接口文档:http://192.168.136.160:3000/project/19/interface/api/151

1.3.2、代码实现

MovementController

1. /**
2.      * 根据id查询动态
3.      */
4. @GetMapping("/{id}")
5. public ResponseEntity findById(@PathVariable("id") String movementId) {
6. MovementsVo vo = movementService.findMovementById(movementId);
7. return ResponseEntity.ok(vo);
8.     }

MovementService

1. public MovementsVo findMovementById(String movementId) {
2. Movement movements = movementApi.findById(movementId);
3. if(movements == null) {
4. return null;
5.     }else {
6. UserInfo userInfo = userInfoApi.findById(movements.getUserId());
7. return MovementsVo.init(userInfo,movements);
8.     }
9. }

movementApi

1. @Override
2. public Movement findById(String movementId) {
3. return mongoTemplate.findById(movementId,Movement.class);
4. }

2、圈子互动

点赞、喜欢、评论等均可理解为用户对动态的互动。

数据库表:quanzi_comment

1. 将数据记录到表中:保存到MongoDB中
2. 互动表需要几张:需要一张表即可(quanzi_comment)
3. 里面的数据需要分类:通过字段commentType 1-点赞,2-评论,3-喜欢
4. {
5. "_id" : ObjectId("5fe7f9263c851428107cd4e8"),
6. "publishId" : ObjectId("5fae53947e52992e78a3afa5"),
7. "commentType" : 1,
8. "userId" : NumberLong(1),
9. "publishUserId" : NumberLong(1),
10. "created" : NumberLong(1609038118275),
11. "likeCount" : 0,
12. "_class" : "com.tanhua.domain.mongo.Comment"
13. }

数据存储位置:redismongodb

mongodb中的数据

  • 在动态详情Movement表中,加入喜欢,点赞,评论数量:检查数据库访问压力
  • 互动操作的时候,不要忘记对上面的字段进行维护
  • 圈子互动的表 comment
  • 互动完成(点赞,喜欢):不仅要将数据保存到mongo中,需要记录到redis中
  • 页面查询圈子列表时,可以从redis中判断是否有点赞,和喜欢历史

2.1、环境搭建

2.1.1 创建API接口

1. public interface CommentApi {
2. 
3. }

2.1.2 创建API实现类

1. @DubboService
2. public class CommentApiImpl implements CommentApi {
3. 
4. @Autowired
5. private MongoTemplate mongoTemplate;
6. }

2.1.3 Movement对象

1. @Data
2. @NoArgsConstructor
3. @AllArgsConstructor
4. @Document(collection = "movement")
5. public class Movement implements java.io.Serializable {
6. 
7. private ObjectId id; //主键id
8. //redis实现,使用Mongodb实现
9. private Long pid; //Long类型,用于推荐系统的模型(自动增长)
10. private Long created; //发布时间
11. private Long userId;
12. private String textContent; //文字
13. private List<String> medias; //媒体数据,图片或小视频 url
14. private String longitude; //经度
15. private String latitude; //纬度
16. private String locationName; //位置名称
17. private Integer state = 0;//状态 0:未审(默认),1:通过,2:驳回
18. 
19. //补充字段
20. private Integer likeCount = 0; //点赞数
21. private Integer commentCount = 0; //评论数
22. private Integer loveCount = 0; //喜欢数
23. 
24. //根据评论类型,获取对应的互动数量
25. public Integer statisCount(Integer commentType) {
26. if (commentType == CommentType.LIKE.getType()) {
27. return this.likeCount;
28.         } else if (commentType == CommentType.COMMENT.getType()) {
29. return this.commentCount;
30.         } else {
31. return loveCount;
32.         }
33.     }
34. }

2.1.4 实体类对象

1. package com.tanhua.domain.mongo;
2. 
3. import lombok.AllArgsConstructor;
4. import lombok.Data;
5. import lombok.NoArgsConstructor;
6. import org.bson.types.ObjectId;
7. import org.springframework.data.mongodb.core.mapping.Document;
8. 
9. /**
10.  * 圈子互动表(点赞,评论,喜欢)
11.  */
12. @Data
13. @NoArgsConstructor
14. @AllArgsConstructor
15. @Document(collection = "comment")
16. public class Comment implements java.io.Serializable{
17. 
18. private ObjectId id;
19. private ObjectId publishId;    //发布id
20. private Integer commentType;   //评论类型,1-点赞,2-评论,3-喜欢
21. private String content;        //评论内容  
22. private Long userId;           //评论人   
23. private Long publishUserId;    //被评论人ID
24. private Long created;        //发表时间
25. private Integer likeCount = 0; //当前评论的点赞数
26. 
27. }

2.1.5 VO对象

1. @Data
2. @NoArgsConstructor
3. @AllArgsConstructor
4. public class CommentVo implements Serializable {
5. 
6. private String id; //评论id
7. private String avatar; //头像
8. private String nickname; //昵称
9. 
10. 
11. private String content; //评论
12. private String createDate; //评论时间
13. private Integer likeCount; //点赞数
14. private Integer hasLiked; //是否点赞(1是,0否)
15. 
16. public static CommentVo init(UserInfo userInfo, Comment item) {
17. CommentVo vo = new CommentVo();
18.         BeanUtils.copyProperties(userInfo, vo);
19.         BeanUtils.copyProperties(item, vo);
20.         vo.setHasLiked(0);
21. Date date = new Date(item.getCreated());
22.         vo.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
23.         vo.setId(item.getId().toHexString());
24. return vo;
25.     }
26. }

2.1.6 CommentType枚举

1. /**
2.  * 评论类型:1-点赞,2-评论,3-喜欢
3.  */
4. public enum CommentType {
5. 
6.     LIKE(1), COMMENT(2), LOVE(3);
7. 
8. int type;
9. 
10.     CommentType(int type) {
11. this.type = type;
12.     }
13. 
14. public int getType() {
15. return type;
16.     }
17. }


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6月前
|
NoSQL 搜索推荐 API
day05—圈子互动
day05—圈子互动
51 0
为什么头条和抖音上这么多人月入好几万?
为什么头条和抖音上这么多人月入好几万?
|
NoSQL API Redis
【探花交友】day05—圈子互动(下)
【探花交友】day05—圈子互动(下)
135 0
|
存储 NoSQL API
【探花交友】day04—圈子功能实现(二)
【探花交友】day04—圈子功能实现(二)
142 0
|
API
【探花交友】day04—圈子功能实现(三)
【探花交友】day04—圈子功能实现(三)
83 0
|
存储 SQL 缓存
【探花交友】day04—圈子功能实现(一)
【探花交友】day04—圈子功能实现
122 0
|
NoSQL 程序员 API
【探花交友】day06—即时通信(三)
【探花交友】day06—即时通信(三)
117 0
|
消息中间件 NoSQL 前端开发
【探花交友】day06—即时通信(一)
【探花交友】day06—即时通信
180 0
|
Dubbo NoSQL 应用服务中间件
【探花交友】day06—即时通信(四)
【探花交友】day06—即时通信(四)
181 0
|
JSON 测试技术 API
【探花交友】day06—即时通信(二)
【探花交友】day06—即时通信(二)
118 0