青训营项目实战1

news/2024/11/16 17:43:15/

项目实战

实现掘金青训营报名页码的后端部分

image-20230126130343565

需求描述

  • 展示话题(标题、文字描述)和回帖列表
  • 不考虑前端页面实现,仅实现一个本地web服务
  • 话题和回帖数据用文件存储

附加要求:

  • 支持发布帖子
  • 本地id生成要保证不重复
  • append文件 更新索引要注意Map的并发安全问题

项目概述

示例图如下:

https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ec319dffe6ae49ad977a8d6a092c7d42~tplv-k3u1fbpfcp-watermark.image?

项目分层结构如下:

https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d578dcdb48674044a09f6144daa380af~tplv-k3u1fbpfcp-watermark.image?
  • 数据层:Repository 直接同数据库或数据存储文件打交道,该部分需要对数据做初步的反序列化(将以二进制形式存储的数据转换为对象)并封装对数据的增删改查操作
  • 逻辑层: Service 处理核心业务的逻辑输出,接收Repository层的数据并进行打包封装
  • 视图层:Controller 处理和外部的交互逻辑,将经过上两层处理的数据以客户端需要的格式发送

代码实现

Repository部分:

首先使用map数据结构定义索引(按值查找,感觉像是一个哈希表),仅展示部分关键代码

//使用索引数据结构提高查询速度
var (topicIndexMap map[int64]*TopicpostIndexMap  map[int64][]*Post
)
//将在磁盘中存储的数据映射到内存中的Map
func initTopicIndexMap(filePath string) error {open, err := os.Open(filePath + "topic")if err != nil {return err}scanner := bufio.NewScanner(open)topicTmpMap := make(map[int64]*Topic)for scanner.Scan() {text := scanner.Text()var topic Topicif err := json.Unmarshal([]byte(text), &topic); err != nil {return err}topicTmpMap[topic.Id] = &topic}topicIndexMap = topicTmpMapreturn nil
}

接着实现查询操作

type Topic struct {Id         int64  `json:"id"`Title      string `json:"title"`Content    string `json:"content"`CreateTime int64  `json:"create_time"`
}
//TopicDao没有实际效果,可能是类似c++中的命名空间,用来防止函数重名
type TopicDao struct {
}
var (topicDao  *TopicDaotopicOnce sync.Once
)
func NewTopicDaoInstance() *TopicDao {topicOnce.Do(func() {topicDao = &TopicDao{}})return topicDao
}
//查询操作,直接按值查找
func (*TopicDao) QueryTopicById(id int64) *Topic {return topicIndexMap[id]
}

Service部分

实体:

type PageInfo struct {Topic    *repository.TopicPostList []*repository.Post
}

Service部分要执行的操作如下:

参数校验
准备数据
组装实体
func (f *QueryPageInfoFlow) Do() (*PageInfo, error) {//参数校验if err := f.checkParam(); err != nil {return nil, err}//准备数据if err := f.prepareInfo(); err != nil {return nil, err}//组装实体if err := f.packPageInfo(); err != nil {return nil, err}return f.pageInfo, nil
}
func (f *QueryPageInfoFlow) checkParam() error {if f.topicId <= 0 {return errors.New("topic id must be larger than 0")}return nil
}func (f *QueryPageInfoFlow) prepareInfo() error {//获取topic信息var wg sync.WaitGroupwg.Add(2)go func() {defer wg.Done()topic := repository.NewTopicDaoInstance().QueryTopicById(f.topicId)f.topic = topic}()//获取post列表go func() {defer wg.Done()posts := repository.NewPostDaoInstance().QueryPostsByParentId(f.topicId)f.posts = posts}()wg.Wait() //等待信息从repository层返回return nil
}func (f *QueryPageInfoFlow) packPageInfo() error {f.pageInfo = &PageInfo{Topic:    f.topic,PostList: f.posts,}return nil
}

Controller部分

定义返回的数据格式

type PageData struct {Code int64       `json:"code"`Msg  string      `json:"msg"`Data interface{} `json:"data"`
}

定义QueryPageInfo方法,根据topicId获取返回的数据

func QueryPageInfo(topicIdStr string) *PageData {topicId, err := strconv.ParseInt(topicIdStr, 10, 64)if err != nil {return &PageData{Code: -1,Msg:  err.Error(),}}//调用service层方法获得数据pageInfo, err := service.QueryPageInfo(topicId)if err != nil {return &PageData{Code: -1,Msg:  err.Error(),}}return &PageData{Code: 0,Msg:  "success",Data: pageInfo,}
}

Router部分

该部分主要实现以下操作:

  1. 初始化数据索引
  2. 初始化引擎配置
  3. 构建路由
  4. 启动服务
func main() {//初始化数据索引if err := Init("./data/"); err != nil {os.Exit(-1)}//初始化引擎配置r := gin.Default()//构建路由r.GET("/community/page/get/:id", func(c *gin.Context) {topicId := c.Param("id")topicId = strings.TrimLeft(topicId, ":,")println(topicId)data := cotroller.QueryPageInfo(topicId)c.JSON(200, data)})//启动服务err := r.Run()if err != nil {return}
}

使用postman测试接口:http://localhost:8080/community/page/get/:2

返回的json数据如下:

{"code": 0,"msg": "success","data": {"Topic": {"id": 2,"title": "青训营来啦!","content": "小哥哥,快到碗里来~","create_time": 1650437640},"PostList": [{"id": 6,"parent_id": 2,"content": "小哥哥快来1","create_time": 1650437621},{"id": 7,"parent_id": 2,"content": "小哥哥快来2","create_time": 1650437622},{"id": 8,"parent_id": 2,"content": "小哥哥快来3","create_time": 1650437623},{"id": 9,"parent_id": 2,"content": "小哥哥快来4","create_time": 1650437624},{"id": 10,"parent_id": 2,"content": "小哥哥快来5","create_time": 1650437625}]}
}
      "content": "小哥哥快来4","create_time": 1650437624},{"id": 10,"parent_id": 2,"content": "小哥哥快来5","create_time": 1650437625}]
}

}



http://www.ppmy.cn/news/19657.html

相关文章

面试汇总-Redis-杂项

目录 1、为什么要用Redis/为什么要用缓存 2、Redis是单线程还是多线程&#xff1f; 3、Redis为什么这么快 4、redis和memcached的区别 5、Redis五种数据类型 6、Redis如何做项目的中间缓存层&#xff1f; 7、keys和scan 8、Redis如何缓存10万条数据 9、Redis如何实现分…

3.1(完结)Linux扫盲笔记

1. Linux环境下&#xff0c;输入密码&#xff0c;不回回显(*)。 2.普通用户的密码一定不要和root一样&#xff0c;root一定要安全级别更高。具体的添加账户和修改密码的操作&#xff0c;见蛋哥Linux训练营&#xff0c;第2课&#xff0c;30分钟处。 3.在最高权限(root)&#x…

阿里“云开发“小程序(uniCould)

博主ps&#xff1a; 网上资料少的可怜&#xff0c;哎&#xff0c;腾讯云涨价了&#xff0c;论服务器&#xff0c;我肯定选的阿里&#xff0c;再着你们对比下unicould的报价就知道了&#xff0c;如果有钱就另当别论了。 所以这片博文&#xff0c;博主试过之后&#xff0c;先抛出…

英语学习打卡day5

2023.1.25 1.aqua n.水;溶液;浅绿色 The construction of underground aqua storage tank 地下水储罐的建设 2.do sth for dear life 拼命做某事 If you do something for dear life, you do it with as much effort as possible, usually to avoid danger. 3. 4.swoop …

Linux系统之网络客户端工具

Linux系统之网络客户端工具一、Links工具1.Links工具介绍2.安装Links软件3.Links工具的使用4.打印网页源码输出5.打印url版本到标准格式输出二、wget工具1.wget工具介绍2.安装wget软件3.wget工具的使用三、curl工具1.curl工具的介绍2.curl的常用参数3.curl的基本使用四、scp工具…

JavaScript笔记+案例

前端开发 第四节JavaScript JavaScript&#xff1a;概要 概要&#xff1a; JavaScript&#xff0c;是一门编程语言。浏览器就是JavaScript语言的解释器。 DOM和BOM 相当于编程语言内置的模块。 例如&#xff1a;Python中的re、random、time、json模块等。jQuery 相当于是编程…

Android音频播放有杂音?原来是这个JAVA API接口惹的祸

最近在调试一个基于十年前Android版本的多媒体应用软件时&#xff0c;遇到了音频播放的问题&#xff0c;这里记录问题的发现、分析和处理过程。 有人可能会好奇&#xff0c;十年前的Android版本是什么版本&#xff1f;大家可以去Google网站上查查&#xff0c;就是目前Android网…

Linux中如何给普通用户提权

引言&#xff1a; 北京时间2023/1/26/11:00 &#xff0c;看到这个日期&#xff0c;我第一时间想到的是还有十几天就要开学啦&#xff01;开学我是向往的&#xff0c;但是我并不怎么向往开学的考试&#xff0c;比如什么毛概和什么信息技术&#xff0c;可能是我深知自己在这些课…