青训营项目实战1

news2025/1/10 21:32:01

项目实战

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

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]*Topic
	postIndexMap  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 Topic
		if err := json.Unmarshal([]byte(text), &topic); err != nil {
			return err
		}
		topicTmpMap[topic.Id] = &topic
	}
	topicIndexMap = topicTmpMap
	return 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  *TopicDao
	topicOnce 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.Topic
	PostList []*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.WaitGroup
	wg.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.coloradmin.cn/o/179636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ONE·C || 指针】

总言 C语言&#xff1a;指针的使用介绍。 文章目录总言1、指针初阶1.1、是什么1.2、指针和指针类型1.2.1、指针类型介绍1.2.2、作用一&#xff1a;指针解引用1.2.3、作用二&#xff1a;指针整数1.3、野指针1.3.1、野指针是什么1.3.2、为什么存在野指针1.3.3、如何避免野指针1.4…

ReentrantLock从入门到踢门

1. ReentrantLock是什么Lock提供了比synchronized方法和语句更广泛的锁定操作。 更灵活的结构化&#xff0c;并且支持多个相关联的对象Condition。它实现了Lock、Serializable序列化接口。图1 ReentrantLock实现接口图1.1 Lock1.1.1 lock// 获取锁 void lock();1.1.2 lockInter…

SpringMVC -->ant风格的路径 -->占位符 -->获取请求参数 -->@RequestParam

文章目录SpringMVC支持ant风格的路径SpringMVC支持路径中的占位符SpringMVC获取请求参数通过servletAPI获取通过控制器方法的形参获取请求参数RequestParam注解处理请求参数和控制器方法的形参的映射关系代码样例SpringMVC支持ant风格的路径 &#xff1f;&#xff1a;表示任意的…

爆火微信公众号自定义早安推送,爱她就给她推送

为女朋友打造专属早安推送先上截图电脑端看的效果手机端看的效果一、申请微信公众号测试号二、让他/她扫码关注测试公众号三、新增模板消息四、天气API五、使用 leancloud 部署云函数六、源代码先上截图 电脑端看的效果 手机端看的效果 一、申请微信公众号测试号 https://mp.w…

Kettle(7):插入/更新组件

1 组件介绍 插入/更新组件能够将Kettle抽取的数据&#xff0c;与某个表的数据进行对比&#xff0c;如果数据存在就更新&#xff0c;不存在就插入。 2 需求 修改 t_user中的张三这一行数据&#xff0c;修改age为80 同时&#xff0c;我们想要使用Kettle将 t_user1 中的张三这一…

【编程入门】N种编程语言做个记事本

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 本系列对比云笔记&#xff0c;将更为简化&#xff0c;去掉了网络调用&#xff0…

量化选股——基于多因子模型的量化策略(第1部分—因子测算策略构建)

文章目录1.多因子模型概述2.因子挖掘3.多因子策略4.多因子策略构建基于多因子的策略通用流程Fama-French三因子因子效果测算方法因子测算结论&量化策略构建东西有点多&#xff0c;拆开成多个文章&#xff0c;边写边整合~&#xff0c;应该会分成2部分&#xff1a; 第1部分—…

【每日一道智力题】之坤坤猜生日(面试高频)

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;每日一题 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最…

文本特征工程——下篇

文本特征下篇 针对梯度提升树模型对文本特征进行特征工程&#xff0c;我们需要充分挖掘LabelLabelLabel编码丢失信息&#xff0c;例如上面的名字特征。内部存在非常强的规律&#xff0c;Mr等信息。这些信息反映了性别相关的信息。如果直接进行Label编码就会丢失此类信息&#…

高通平台开发系列讲解(GPS篇)NMEA数据包解析

文章目录 一、通用NMEA语句类型二、 NMEA语句格式2.1、GSV语句2.2、RMC语句2.3、GSA语句2.4、VTG语句2.5、DTM语句2.6、GNS语句2.7、GGA语句2.8、GLL语句2.9、GST语句2.10、ZDA语句沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 NMEA-0183是美国国家海洋电子协会为海…

【读论文】Going deeper in spiking neural networks Vgg and residual architecture

frontiers in Neuroscience 2019 摘要 本文提出一种新的方法来构建深度SNN&#xff0c;并在复杂视觉识别问题上证明其有效性&#xff08;如CIFAR10和ImageNet&#xff09;&#xff1b;该方法应用于VGG和残差网络结构&#xff0c;并获得最优精度&#xff1b;最后给出稀疏事件驱…

力扣刷题| 20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值

文章标题LeetCode 20. 有效的括号题目链接&#x1f517;思路代码实现LeetCode 1047. 删除字符串中的所有相邻重复项题目链接&#x1f517;思路代码实现LeetCode 150. 逆波兰表达式求值题目链接&#x1f517;思路代码实现LeetCode 20. 有效的括号 题目链接&#x1f517; LeetC…

运动基元(一):Dubin‘s曲线【part2】

三、六种Dubin’s轨迹的实现——开始摆盘啦 3.1 LSL LSL的第一段圆弧的曲率 k 1 = k m a x > 0 → s i g n ( k 1 ) = 1 k_1=k_{max}>0\rightarrow

118、【回溯算法】leetcode ——40. 组合总和 II:回溯法+剪枝优化(C++版本)

题目描述 原题链接&#xff1a;40. 组合总和 II 解题思路 本题的特点是&#xff0c;一个允许结果中出现相同数字&#xff0c;但每个元素仅能被选取一次。结果与结果之间不允许有重复&#xff0c;需要去重。 与 77. 组合&#xff08;回溯法剪枝优化&#xff09; 的相同之处在于…

【JavaSE专栏9】Java 注释知多少

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

斐波那契数列的--------5种算法(又称“兔子数列”)

斐波那契数列&#xff08;Fibonacci sequence&#xff09;&#xff0c;又称黄金分割数列&#xff0c;因数学家莱昂纳多斐波那契&#xff08;Leonardo Fibonacci&#xff09;以兔子繁殖为例子而引入&#xff0c;故又称为“兔子数列”&#xff0c;指的是这样一个数列&#xff1a;…

决策树-剪枝处理

前言&#xff1a;理解《机器学习》P79-83中的决策树剪枝示例。 决策树生成 原始数据集如下所示&#xff0c;前10行为训练集&#xff0c;后7行为验证集&#xff0c;由此数据集可生成如下所示的决策树。 下面解释未进行剪枝操作的决策树为何如上图所示。 不对解释每个结点和分支…

WPF-3D图形

WPF-3D图形 WPF的3D功能可以在不编写任何c#代码的情况下进行绘制&#xff0c;只需要使用xaml即可完成3D图形的渲染。本文主要讲述了WPF-3D中的关键概念&#xff0c; 以及常用到的命中测试、2d控件如何在3D对象中进行渲染&#xff0c;除此之外&#xff0c;还演示了如何导入外部…

InstanceNorm LayerNorm

InstanceNorm && LayerNorm author: SUFEHeisenberg date: 2023/01/26 先说结论: 将Transformer类比于RNN&#xff1a;一个token就是一层layer&#xff0c;对一整句不如token有意义原生Bert代码或huggingface中用的都是InstanceNorm instead of LayerNorm&#xff…

【AAAI2023】Head-Free Lightweight Semantic Segmentation with Linear Transformer

论文&#xff1a;【AAAI2023】Head-Free Lightweight Semantic Segmentation with Linear Transformer 代码&#xff1a;https://github.com/dongbo811/AFFormer 这是来自阿里巴巴的工作&#xff0c;作者构建了一个轻量级的Transformer网络用于语义分割&#xff0c;主要有两点…