租售同体的书屋项目——书籍系统(二)——第三部分(评论) 一

一、概述

书籍系统框架如图:

书籍系统.png

文件内容持续更新在GitHub上,可自行查看。

本篇主要是介绍:评论和阅读量中的评论

二、评论

思路

1.对文章的评论

2.对评论的回复

3.让数据呈现树状结构

数据库设计

评论数据表设计.png

parent_id指向父评论id,如果是文章的评论默认为0.

代码

1.因为评论是树状结构,所以在微服务部分做了树数据的嵌套。

action.proto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
protobuf复制代码syntax = "proto3";

package action;

option go_package = "action";

message Request {
string ping = 1;
}

message Response {
bool ok = 1;
string message = 2;
}

message CommentReq{
int64 Id = 1;
int64 ParentId = 2;
int64 BookContentId = 3;
string Comment = 4;
int64 CommentByUserId = 5;
string CommentByNickname = 6;
int64 CommentToUserId = 7;
string CommentToNickname = 8;
}

message CommentResp{
int64 Id = 1;
int64 ParentId = 2;
int64 BookContentId = 3;
string Comment = 4;
int64 CommentByUserId = 5;
string CommentByNickname = 6;
int64 CommentToUserId = 7;
string CommentToNickname = 8;
}

message CommentsNodeResp{
CommentResp Comments = 1;
repeated CommentsNodeResp CommentsNode = 2;
}

message CommentsTreeResp{
repeated CommentsNodeResp CommentsTree = 1;
}

service Action {
//Comments
rpc GetCommentsByBookContentId(CommentReq) returns(CommentsTreeResp);
rpc CreateComment(CommentReq) returns(Response);
rpc UpdateComment(CommentReq) returns(Response);
rpc DeleteComment(CommentReq) returns(Response);
}

2.在逻辑代码中把数据库中的数据组合成树数据

getcommentsbybookcontentidlogic.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
golang复制代码// Comments
func (l *GetCommentsByBookContentIdLogic) GetCommentsByBookContentId(in *action.CommentReq) (*action.CommentsTreeResp, error) {
comments, err := l.svcCtx.CommentModel.FindCommentsByBookContentId(in.BookContentId)
if err != nil {
return nil, err
}
fmt.Println("comments", comments)

f := func(cs []*model.Comment) *action.CommentsTreeResp {
//树结构
var res = action.CommentsTreeResp{
CommentsTree: make([]*action.CommentsNodeResp, 0),
}
for i := 0; i < len(cs); i++ {
if cs[i].ParentId == 0 {
res.CommentsTree = append(res.CommentsTree, &action.CommentsNodeResp{
Comments: &action.CommentResp{
Id: cs[i].Id,
ParentId: cs[i].ParentId,
BookContentId: cs[i].BookContentId,
Comment: cs[i].Comment,
CommentByUserId: cs[i].CommentByUserId,
CommentByNickname: cs[i].CommentByNickname,
CommentToUserId: cs[i].CommentToUserId,
CommentToNickname: cs[i].CommentToNickname,
},
})
} else {
node := FindCommentNodeByParentId(res.CommentsTree, cs[i].ParentId)
if node != nil {
node.CommentsNode = append(node.CommentsNode, &action.CommentsNodeResp{
Comments: &action.CommentResp{
Id: cs[i].Id,
ParentId: cs[i].ParentId,
BookContentId: cs[i].BookContentId,
Comment: cs[i].Comment,
CommentByUserId: cs[i].CommentByUserId,
CommentByNickname: cs[i].CommentByNickname,
CommentToUserId: cs[i].CommentToUserId,
CommentToNickname: cs[i].CommentToNickname,
},
})
}
}
}
return &res
}
return f(comments), nil
}

//找到id对应的节点
func FindCommentNodeByParentId(res []*action.CommentsNodeResp, id int64) *action.CommentsNodeResp {
for i := 0; i < len(res); i++ {
if id == res[i].Comments.Id {
return res[i]
} else {
if r := FindCommentNodeByParentId(res[i].CommentsNode, id); r != nil {
return r
}
}
}
return nil
}

3.在做前端的时候,发现评论一般都是只有父子两级,所以在WebApi中把所有的对评论的回复又组合成子级。–!有苦说不出。

get_comment_handler.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
golang复制代码package action

import (
"WebApi/Pb/action"
"WebApi/Svc"
"context"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)

func GetCommentsByBookContentIdHandler(c *gin.Context) {
bookContentId, err := strconv.ParseInt(c.Query("bookContentId"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
ctx := context.Background()
//树状结构(评论)
res, err := Svc.SvcContext.Grpc.ActionGrpc.GetCommentsByBookContentId(ctx, &action.CommentReq{
BookContentId: bookContentId,
})
//树状结构 平铺为 只有父子节点结构(评论) 方便前端使用
tn := func(t *action.CommentsTreeResp) action.CommentsTreeResp {
var tree = action.CommentsTreeResp{}
for i := 0; i < len(t.CommentsTree); i++ {
//组合父节点
tree.CommentsTree = append(tree.CommentsTree, &action.CommentsNodeResp{
Comments: t.CommentsTree[i].Comments,
})
//组合父节点下所有的节点
combChildComment(t.CommentsTree[i].CommentsNode, &tree.CommentsTree[i].CommentsNode)
}
return tree
}

if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, tn(res))
}
}

func combChildComment(src []*action.CommentsNodeResp, dest *[]*action.CommentsNodeResp) {
for i := 0; i < len(src); i++ {
*dest = append(*dest, &action.CommentsNodeResp{
Comments: src[i].Comments,
})
if src[i].CommentsNode != nil {
combChildComment(src[i].CommentsNode, dest)
}
}

}

4.POSTman的结果展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
postman复制代码{
"CommentsTree": [
{
"Comments": {
"Id": 1,
"BookContentId": 2,
"Comment": "写得好。",
"CommentByUserId": 1,
"CommentByNickname": "书店老板",
"CommentToUserId": 1,
"CommentToNickname": "书店老板"
},
"CommentsNode": [
{
"Comments": {
"Id": 3,
"ParentId": 1,
"BookContentId": 2,
"Comment": "马屁精。",
"CommentByUserId": 2,
"CommentByNickname": "张三",
"CommentToUserId": 1,
"CommentToNickname": "书店老板"
}
},
{
"Comments": {
"Id": 4,
"ParentId": 3,
"BookContentId": 2,
"Comment": "来来来,笔给你,你来写",
"CommentByUserId": 3,
"CommentByNickname": "李四",
"CommentToUserId": 2,
"CommentToNickname": "张三"
}
}
]
},
{
"Comments": {
"Id": 5,
"BookContentId": 2,
"Comment": "写得好1。",
"CommentByUserId": 1,
"CommentByNickname": "书店老板",
"CommentToUserId": 1,
"CommentToNickname": "书店老板"
},
"CommentsNode": [
{
"Comments": {
"Id": 8,
"ParentId": 5,
"BookContentId": 2,
"Comment": "不好",
"CommentByUserId": 4,
"CommentByNickname": "王五",
"CommentToUserId": 1,
"CommentToNickname": "书店老板"
}
},
{
"Comments": {
"Id": 9,
"ParentId": 8,
"BookContentId": 2,
"Comment": "不好才怪",
"CommentByUserId": 4,
"CommentByNickname": "王五",
"CommentToUserId": 4,
"CommentToNickname": "王五"
}
}
]
},
{
"Comments": {
"Id": 10,
"BookContentId": 2,
"Comment": "我是第一",
"CommentByUserId": 4,
"CommentByNickname": "王五",
"CommentToUserId": 4,
"CommentToNickname": "王五"
}
},
{
"Comments": {
"Id": 11,
"BookContentId": 2,
"Comment": "第二",
"CommentByUserId": 4,
"CommentByNickname": "王五",
"CommentToUserId": 4,
"CommentToNickname": "王五"
}
},
{
"Comments": {
"Id": 12,
"BookContentId": 2,
"Comment": "文章YYDS。",
"CommentByUserId": 1,
"CommentByNickname": "书店老板",
"CommentToUserId": 1,
"CommentToNickname": "书店老板"
}
}
]
}

5.前端成果展示

评论.png

三、Tips

最近工作中忙了起来,更新可能会比之前慢一些,请多多包涵。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%