# 干货场景 - “我的评论点赞列表”
介绍
我们通常能在一个交互平台看到我们的优质评论被点赞的信息, 但这看似
简单的效果, 实则却是疯狂的复杂结构, 接下来教你如何简单完成这一需求
我们先来看最终的显示效果
从这里我们可以看到几个主要信息
- 右边
>>
我的评论 - 左边
<<
点赞的信息 - 左边
<<
点赞的时间
由此我们可以获得这个表的设计 我的评论点赞列表 comment_like
列 | 类型 | 描述 |
---|---|---|
comment_id | INT | 我的评论(外键,关联评论表) |
user_id | INT | 点赞的用户 (外键,关联用户表) |
created_at | DATETIME | 点赞时间 |
该表关系为一对多
(实质为多对多), 表示 一个评论被多个用户点赞
, 为了方便演示, 我们再补全 评论
和 用户
这两张表
用户评论表
列 | 类型 | 描述 |
---|---|---|
comment_id | INT | 主键 |
created_at | DATETIME | 发送评论时间 |
status | TINYINT | 评论状态 0-撤回 1-正常 2-违规 3-待审核 |
like_num | INT | 点赞量 |
u_id | INT | 外键, 绑定发评论的用户 |
iss_id | INT | 评论的视频 (作品) |
用户表
列 | 类型 | 描述 |
---|---|---|
u_id | INT | 主键 |
name | VARCHAR | 用户昵称 |
picture | VARCHAR | 图片URL |
. . . |
开始
请求
-
首先进入这个页面, 获取这个数据, 就需要前端传递这个用户的编号
/comments/{u-id}/comment-likes
表示 : 当前用户发布所有评论 的点赞列表 -
后端通过 前端传递的
u-id
就可以在评论表中连接
发评论的用户, 过滤出当前用户的所有评论, 但单这样我们是拿不到以下数据的预期效果
-
也就是说, 我们要查询的主表不是 评论表, 而是
评论点赞列表
, 我们需要通过该列表的评论外键comment_id
, 去连接发评论的用户 = 前端传递的{u-id}
select (省略) from comment_like 点赞列表 join comment 评论 on 点赞列表.cm_id = 评论.cm_id where 评论.u_id = #{u_id} -- 前端传递的 当前用户编号 order by 点赞列表.created_at
响应
正确处理请求后, 我们要考虑的就是响应格式了
我们从图片中分析响应格式, 其中应该包含数组嵌套对象, 对象嵌套数组, 那么一般的响应格式是满足不了我们的, 就像上方 sql
更不满足图中的要求, 那我们就不得不避开一般的响应格式, 使用 “DTO
”
DTO 是什么?
就是为了定义和封装 响应数据格式 或 请求数据格式 而创建的类。
-
我们先根据图片慢慢分析, 从图片中获取的信息
- 用户 >> 头像
- 用户 >> 昵称
- 评论 >> 内容
- 最近的点赞时间
-
根据梳理结合图片, 可以明白返回格式首先是一个数组, 并且数组里有多个对象, 对象包含
-
最新的点赞时间
created_at
, 从多个点赞的用户当中选出最早点赞的示例 sql 返回的数据
点赞的用户 点赞的时间 create_at **点赞的用户 **u_id 我的评论 comment_id 第一个 2020年9月10日 9:16:00 1001 1 第二个 2020年9月10日 9:16:02 1002 1 第三个 (这个是评论1最新的点赞!) 2020年9月10日 9:16:03 1003 1 第一个 2020年9月10日 9:17:00 1001 2 第二个 (这个是评论2最新的点赞!) 2020年9月10日 9:17:02 1002 2 表格示例中, 直到下一个评论 前
我的评论
一直不变, 而点赞的用户一直在变, 所以数组中的单个对象就对应
着单个我的评论, 而点赞我的用户则是一个集合, 由此可得以下格式 -
对象里嵌套 点赞的用户对象, 其中包含用户的信息
{ "code": 200, "msg": "success", "data": [ { "created_at": "2024年8月12日 11:49", "users": [ { "uId": 1, "name": "懒懒不想想" }, { "uId": 2, "name": "宇宙最帅莫漓酱" } ], "comment": { "cmId": 1, "content": "好可爱", "likeNum": 12 } } ] }
-
定义这三个表对应的DTO对象 (DTO 对象后缀一般为 Response, Request)
// 评论点赞列表DTO public class CommentLikeResp { private String creTime; private CommentResponse comment; private List<UserResponse> users; // Getters and Setters } // 我的评论DTO public class CommentResp { private Integer cmId; private String content; // 需要从 UserComment 中获取 private Integer likeNum; // Getters and Setters } // 点赞的用户DTO public class UserResp { private Integer uId; private String name; // Getters and Setters }
-
编写 查询所有用户评论点赞列表的 sql 语句
@Mapper public interface CommentLikeMapper { @Select(""" select * from comment_like as 点赞列表 join comment as 评论 on 点赞列表.cm_id = 评论.cm_id where 评论.u_id = #{uId} order by 点赞列表.created_at """) List<CommentLike> getCommentLikesByUserId(Integer uId); }
-
事务层进行格式封装
public List<CommentLikeResp> getCommentLikesByUser Id(Integer uId) { List<CommentLike> likes = commentLikeMapper.getCommentLikesByUId(uId); List<CommentLikeResp> respList = new ArrayList<>(); Map<Integer, CommentLikeResp> respMap = new HashMap<>(); for (CommentLike like : likes) { // 获取或创建 CommentLikeResp 对象 CommentLikeResp response = respMap.get(like.getComment().getId()); if (response == null) { // 创建新的 CommentResp 对象 CommentResp commentResponse = new CommentResp( like.getComment().getId(), like.getComment().getContent(), like.getComment().getLikeNum() // 假设 Comment 类有这个方法 ); // 创建新的 CommentLikeResp 对象 response = new CommentLikeResp( like.getCreatedAt(), new ArrayList<>(), // 初始化用户列表 commentResponse ); // 将新创建的响应对象放入 Map 中 respMap.put(like.getComment().getId(), response); } // 添加用户信息 UserResp userResponse = new UserResp(like.getUser ().getId(), like.getUser ().getName()); response.getUsers().add(userResponse); } // 将 Map 中的所有响应对象转换为列表 respList.addAll(respMap.values()); return respList; }
以下是逐步拆解 (实际上sql 返回就是点赞列表, 只是格式不符, 所以该方法仅是为了返回一个格式而已)
主要思路 :
通过已有点赞列表获取DTO对象, 但实际上DTO对象最初并没有数据
而是通过后续的if 条件一步步生成的
而获取DTO对象是为了确保当前评论
下有对应的点赞用户而不受乱序
影响 (如果你读懂了这句段落接下来就可以不用看了, 你已经会啦)
1. 遍历点赞记录
for (CommentLike like : likes) {
目的:
遍历所有点赞记录,将每条记录根据其评论ID分组,同时将点赞用户信息添加到对应的分组中。
2. 获取或创建
CommentLikeResp
对象CommentLikeResp response = respMap.get(like.getComment().getId()); if (response == null) { // 创建新的 CommentResp 对象 CommentResp commentResponse = new CommentResp( like.getComment().getId(), like.getComment().getContent(), like.getComment().getLikeNum() ); // 创建新的 CommentLikeResp 对象 response = new CommentLikeResp( like.getCreatedAt(), new ArrayList<>(), // 初始化用户列表 commentResponse ); // 将新创建的响应对象放入 Map 中 respMap.put(like.getComment().getId(), response); }
目的:
对每条点赞记录,判断是否已经有一个对应的CommentLikeResp
对象存在:- 如果存在: 直接获取,避免重复创建对象。
- 如果不存在:
- 创建
CommentResp
对象: 封装评论的信息(评论ID、内容、点赞数)。 - 创建
CommentLikeResp
对象: 封装评论和点赞相关的信息,包括点赞时间(createdAt
)和一个空的用户列表。 - 存入
respMap
: 将新创建的CommentLikeResp
对象以评论ID为键存入映射,方便后续操作。
- 创建
3. 添加用户信息到
CommentLikeResp
UserResp userResponse = new UserResp(like.getUser().getId(), like.getUser().getName()); response.getUsers().add(userResponse);
目的:
将当前点赞记录中的用户信息(用户ID、用户名)封装成UserResp
对象,并添加到对应的CommentLikeResp
对象的用户列表中。UserResp
: 是一个 DTO 类,用于封装用户信息(用户ID、用户名)。response.getUsers().add(userResponse)
: 将用户添加到当前评论的用户列表中,表示该用户对这条评论点了赞。
4. 将分组结果转换为列表
respList.addAll(respMap.values());
目的:
遍历respMap
中的所有CommentLikeResp
对象,将其转换为列表并存入respList
。respMap.values()
: 获取所有分组后的CommentLikeResp
对象。- 最终的
respList
: 包含按评论分组的点赞记录,符合预期的返回格式。
-
剩下的只显示两个或一个用户就简单了,
End
如果这篇文章帮到你, 帮忙点个关注呗, 点赞或收藏也行鸭 ~ (。•ᴗ-)✧
^ '(இ﹏இ`。)