主要是对项目模块的分析梳理
功能
主要是实现展示具体的话题和其回帖
数据存储
根据上图设计对应的结构体
// topic.go
type Topic struct {
Id int64 `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
CreateTime int64 `json:"create_time"`
}
// post.go
type Post struct {
Id int64 `json:"id"`
ParentId int64 `json:"parent_id"`
Content string `json:"content"`
CreateTime int64 `json:"create_time"`
}
实现结构
数据层
项目并没有让用户对数据的直接访问,而是通过DAO对象提供的接口来获取数据。让逻辑层不用知道我到底是用redis还是sql又或者是直接文件存储数据,只需要访问DAO接口即可。
type TopicDao struct {
}
var (
topicDao *TopicDao
topicOnce sync.Once
)
func NewTopicDaoInstance() *TopicDao {
topicOnce.Do(
func() {
topicDao = &TopicDao{}
})
return topicDao
}
func (*TopicDao) QueryTopicById(id int64) *Topic {
return topicIndexMap[id]
}
type PostDao struct {
}
var (
postDao *PostDao
postOnce sync.Once
)
func NewPostDaoInstance() *PostDao {
postOnce.Do(
func() {
postDao = &PostDao{}
})
return postDao
}
func (*PostDao) QueryPostsByParentId(parentId int64) []*Post {
return postIndexMap[parentId]
}
func NewTopicDaoInstance() *TopicDao // 获取话题DAO
func (*PostDao) QueryPostsByParentId(parentId int64) []*Post // 根据话题id获取回复
func NewPostDaoInstance() *PostDao // 获取回复DAO
func (*TopicDao) QueryTopicById(id int64) *Topic // 根据话题id获取话题
使用单例模式,使用sync.Once来保证只被创建一次。采用了建立索引的方式来提高性能,在上述函数中只需要直接根据id就可以获取map相应内容。
具体如下:
func initPostIndexMap(filePath string) error{
open, err := os.Open(filePath + "post")
if err != nil {
return err
}
scanner := bufio.NewScanner(open)
postTmpMap := make(map[int64][]*Post)
for scanner.Scan() {
text := scanner.Text()
var post Post
if err := json.Unmarshal([]byte(text), &post); err != nil {
return err
}
posts, ok := postTmpMap[post.ParentId]
if !ok {
postTmpMap[post.ParentId] = []*Post{&post}
continue
}
posts = append(posts, &post)
postTmpMap[post.ParentId] = posts
}
postIndexMap = postTmpMap
return nil
}
初始化postIndexMap变量。该函数从指定的文件中读取内容,并将其解析为Post结构体的集合,然后将这些结构体按照ParentId进行索引存储在postIndexMap中。
逻辑层
前面数据层对存储数据进行了封装给出了DAO接口,逻辑层的任务则是将DAO接口进一步封装,以给视图层提供更加高级的访问接口。
type PageInfo struct {
Topic *repository.Topic
PostList []*repository.Post
}
// 根据id给出页面信息,包括话题和回复列表
func QueryPageInfo(topicId int64) (*PageInfo, error)
视图层
调用逻辑层service的接口将操作封装给最终的客户: pageInfo, err := service.QueryPageInfo(topicId)
type PageData struct {
Code int64 `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
func QueryPageInfo(topicIdStr string) *PageData {
topicId, err := strconv.ParseInt(topicIdStr, 10, 64)
if err != nil {
return &PageData{
Code: -1,
Msg: err.Error(),
}
}
pageInfo, err := service.QueryPageInfo(topicId)
if err != nil {
return &PageData{
Code: -1,
Msg: err.Error(),
}
}
return &PageData{
Code: 0,
Msg: "success",
Data: pageInfo,
}
}
Server
客户通过调用cotroller层的API对帖子进行查询到达视图层,cotroller调用service的API进行查询到达逻辑层,逻辑层通过DAO去访问数据层,进而到达数据库查询数据,返回结果。
r.GET("/community/page/get/:id", func(c *gin.Context) {
topicId := c.Param("id")
data := cotroller.QueryPageInfo(topicId)
c.JSON(200, data)
}