An overview,

The book system framework is shown as follows:

File content is continuously updated inGitHubOn, you can check by yourself.

This article mainly introduces: reviews and readingsIn thecomments

Second, the commentary

Train of thought

1. Comments on the article

2. Responses to comments

3. Tree your data

Database design

Parent_id points to the parent comment ID, which defaults to 0 if it is an article comment.

code

1. Because comments are tree-like structures, nesting of tree data is done in the micro-service part.

action.proto

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);
}
Copy the code

2. Combine database data into tree data in logical code

getcommentsbybookcontentidlogic.go

// Comments
func (l *GetCommentsByBookContentIdLogic) GetCommentsByBookContentId(in *action.CommentReq) (*action.CommentsTreeResp, error) {
	comments, err := l.svcCtx.CommentModel.FindCommentsByBookContentId(in.BookContentId)
	iferr ! =nil {
		return nil, err
	}
	fmt.Println("comments", comments)

	f := func(cs []*model.Comment) *action.CommentsTreeResp {
		/ / tree structure
		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)
				ifnode ! =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
}

// Find the node corresponding to the 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 {
			ifr := FindCommentNodeByParentId(res[i].CommentsNode, id); r ! =nil {
				return r
			}
		}
	}
	return nil
}
Copy the code

3. When doing the front end, I found that comments generally only have two levels of father and son, so I combined all the replies to comments into sub-levels in WebApi. – -! There is bitter can not speak out.

get_comment_handler.go

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)
	iferr ! =nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	ctx := context.Background()
	// Tree structure (comment)
	res, err := Svc.SvcContext.Grpc.ActionGrpc.GetCommentsByBookContentId(ctx, &action.CommentReq{
		BookContentId: bookContentId,
	})
	// Tree structure tiling for only parent-child node structure (comments) easy front-end use
	tn := func(t *action.CommentsTreeResp) action.CommentsTreeResp {
		var tree = action.CommentsTreeResp{}
		for i := 0; i < len(t.CommentsTree); i++ {
			// Combine the parent node
			tree.CommentsTree = append(tree.CommentsTree, &action.CommentsNodeResp{
				Comments: t.CommentsTree[i].Comments,
			})
			// Combine all nodes under the parent node
			combChildComment(t.CommentsTree[i].CommentsNode, &tree.CommentsTree[i].CommentsNode)
		}
		return tree
	}

	iferr ! =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,
		})
		ifsrc[i].CommentsNode ! =nil {
			combChildComment(src[i].CommentsNode, dest)
		}
	}

}
Copy the code

4.POSTman’s results show

{"CommentsTree": [{"Comments": {"Id": 1, "BookContentId": 2, "Comment": "well written. ", "CommentByUserId": 1, "CommentByNickname": "bookshop owner ", "CommentToUserId": 1, "CommentToNickname":" bookshop owner "}, "CommentsNode": [{"Comments": {"Id": 3, "ParentId": 1, "BookContentId": 2, "Comment": "flatterer ", "CommentByUserId": 2, "CommentByNickname": "CommentToUserId": 1, "CommentToNickname": "Bookkeeper"}}, {"Comments": {"Id": 4, "ParentId": 3, "BookContentId": "CommentByUserId": 3, "CommentByNickname": 3, "CommentToUserId": }}]}, {"CommentToNickname": {"Id": 5, "BookContentId": 2, "Comment": "Well written 1. ", "CommentByUserId": 1, "CommentByNickname":" Bookstore owner ", "CommentToUserId": 1, "CommentToNickname": }, "CommentsNode": [{"Comments": {"Id": 8, "ParentId": 5, "BookContentId": 2, "Comment": "Not good ", "CommentByUserId": 4, "CommentByNickname":" King five ", "CommentToUserId": 1, "CommentToNickname": }}, {"Comments": {"Id": 9, "ParentId": 8, "BookContentId": 2, "Comment": "bad ", "CommentByUserId": 4, "CommentByNickname": "CommentToUserId": 4, "CommentToNickname": "CommentToNickname"}}]}, {"Comments": {"Id": 10, "BookContentId": 2, "Comment": "I am the first ", "CommentByUserId": 4, "CommentByNickname":" King five ", "CommentToUserId": }}, {"Comments": {"Id": 11, "BookContentId": 2, "Comment": "2 ", "CommentByUserId": 4, "CommentByNickname": "CommentToUserId": 4, "CommentToNickname": "CommentToNickname"}}, {"Comments": {"Id": 12, "BookContentId": 2, "Comment": "article YYDS. ", "CommentByUserId": 1, "CommentByNickname":" Bookseller ", "CommentToUserId": 1, "CommentToNickname": "Bookshop owner"}}]}Copy the code

5. Front-end results display

Three, Tips,

I have been busy with my work recently, so the update may be slower than before, please bear with me.