GO语言工程实践课 | 青训营

66 阅读2分钟

主要是对项目模块的分析梳理

功能

主要是实现展示具体的话题和其回帖

图片.png

图片.png

数据存储

根据上图设计对应的结构体

// 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"`
}

实现结构

Untitled 10.png

数据层

项目并没有让用户对数据的直接访问,而是通过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)
}