说一下为什么要做这个,这段时间做毕设需要这个功能,然后今天搞了一天,我不太擅长搞后端,看了好久,也算是记录一下自己的学习,毕竟答辩的时候还需要呢。
先上效果图(我看别人博客老是没有效果就很烦)
说一下大致思路(实现两级):(判题系统)
- 前端通过当前问题的id去请求后端,然后后端查询关于此题目的相关评论集合返回给前端
- 添加评论,这个通过当前题目的id,和评论id,当前用户的id,如果是二级评论则要targetId即子级评论。
- 在添加的时候要想明白,一级评论,二级评论之间关系,怎么去区分,我做的时候他们的请求参数不一样,二级评论的参数要加上 parentId和targetId这样才能形成嵌套关系,从遍历获取即可。(补充这里的还应该返回每条评论的user对象,用于获取用户头像,用户名等)
数据库设计:
CREATE TABLE `comment` (
`id` bigint NOT NULL COMMENT '评论id',
`content` varchar(255) NOT NULL COMMENT '评论内容',
`questionId` bigint NOT NULL COMMENT '题目id',
`userId` bigint NOT NULL COMMENT '评论人id',
`userAvatar` varchar(1024) DEFAULT NULL COMMENT '用户头像',
`userName` varchar(25) DEFAULT NULL COMMENT '用户昵称',
`parentId` bigint DEFAULT NULL COMMENT '评论父级id',
`targetId` bigint DEFAULT NULL COMMENT '回复目标对象id',
`createTime` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`isDelete` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0未删除 1删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
JavaBean:
/**
* 评论id
*/
@TableId
private Long id;
/**
* 评论内容
*/
private String content;
/**
* 题目id
*/
private Long questionId;
/**
* 评论人id
*/
private Long userId;
/**
* 用户头像
*/
private String userAvatar;
/**
* 用户昵称
*/
private String userName;
/**
* 评论父级id
*/
private Long parentId;
/**
* 回复目标对象id
*/
private Long targetId;
/**
* 创建时间
*/
private Date createTime;
/**
* 是否删除 0未删除 1删除
*/
private Integer isDelete;
/**
* 子评论
* */
private List<Comment> children;
添加实现:
@PostMapping("/add")
public BaseResponse<Long> addComment(@RequestBody CommentAddRequest commentAddRequest, HttpServletRequest request) {
if (commentAddRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
Comment comment = new Comment();
BeanUtils.copyProperties(commentAddRequest, comment);
User loginUser = userService.getLoginUser(request);
comment.setUserId(loginUser.getId());
comment.setCreateTime(new Date());
boolean result = commentService.save(comment);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
Long newCid = comment.getId();
return ResultUtils.success(newCid);
}
条件查询实现:
/**
* 根据 id 获取
*
* @param id
* @return 根据id获取当前题目下的评所有评论
*/
@GetMapping("/get")
public BaseResponse<List<Comment>> getCommentByQuestionId(Long id, HttpServletRequest request) {
return ResultUtils.success(commentService.getComment(id, request));
}
评论如何返回给前端最重要的就是这个方法:
/**
* 构建评论树
* @param list
* @return
*/
public static List<Comment> processComments(List<Comment> list) {
Map<Long, Comment> map = new HashMap<>(); // (id, Comment)
List<Comment> result = new ArrayList<>();
// 将所有根评论加入 map
for(Comment comment : list) {
if(comment.getParentId() == null)
result.add(comment);
map.put(comment.getId(), comment);
}
// 子评论加入到父评论的 children 中
for(Comment comment : list) {
Long id = comment.getParentId();
if(id != null) { // 当前评论为子评论
Comment p = map.get(id);
if(p.getChildren() == null) // children 为空,则创建
p.setChildren(new ArrayList<>());
p.getChildren().add(comment);
}
}
return result;
}
返回数据格式 :
{
"id": "1774656313639944193",
"content": "gvyfasgfgsayugfhas",
"questionId": "1",
"userId": "1771795740782833666",
"userAvatar": null,
"userName": "",
"parentId": null,
"targetId": null,
"createTime": "2024-04-01T07:28:10.000+00:00",
"isDelete": 0,
"children": [
{
"id": "1774797768555577345",
"content": " 就这难度",
"questionId": "1",
"userId": "1771924522776735746",
"userAvatar": null,
"userName": null,
"parentId": "1774656313639944193",
"targetId": null,
"createTime": "2024-04-01T13:55:37.000+00:00",
"isDelete": 0,
"children": null
}
]
}
前端调用接口通过v-for遍历
如果children不为null 嵌套遍历
我使用的是arco-design组件库Arco Design Vue
然后就没有什么较难的啦
时间转换使用的是moment().format("LLL");