Go学习笔记(三)项目实战——完成社区话题的后端逻辑

简介: 项目要求:完成社区话题的后端逻辑
本文首发于稀土掘金。该平台的作者 逐光而行 也是本人。

参考资料

  • 字节跳动第三届青训营后端专场课程公开资料

https://juejin.cn/post/7093721879462019102

  • 一位大佬写的青训营笔记

https://juejin.cn/post/7096064144180248612

项目要求

  1. 为社区话题页面实现一个web服务(不涉及前端),要求可展示话题(标题、文字描述)以及其下的回帖列表
  2. 不涉及数据库,仅涉及本地文件存储
  3. 可对话题进行回帖,回帖id唯一
  4. 注意Map并发性问题

项目地址

!!!注:以下是对参考代码的学习!!!

参考代码为github项目中的v0.1分支

E-R图设计及类字段描述

image.png

  • 每个Topic有一个独特的id,每个属于该Topic的Post都关联该id字段;每条Post的id也是唯一的(topic_id);
  • Topic有标题、内容、创建时间;Post也有自己的内容、创建时间

分层结构设计

后端不止是对数据进行增删查改,从文件(数据库)到客户,其实还分为以下几层:

  • 数据层:数据模型,对数据进行增删查改。
  • 逻辑层:业务实体,处理核心业务逻辑输出。
  • 控制层,展现视图,处理和外部的交互逻辑。

image.png

Web框架Gin

web 框架:Gin - github.com/gin-gonic/g…

用于写一个发帖接口。
Gin示例代码如下:

func main() {
  // Creates a gin router with default middleware:
  // logger and recovery (crash-free) middleware
  router := gin.Default()

  router.GET("/someGet", getting)
  router.POST("/somePost", posting)
  router.PUT("/somePut", putting)
  router.DELETE("/someDelete", deleting)
  router.PATCH("/somePatch", patching)
  router.HEAD("/someHead", head)
  router.OPTIONS("/someOptions", options)

  // By default it serves on :8080 unless a
  // PORT environment variable was defined.
  router.Run()
  // router.Run(":3000") for a hard coded port
}

接口代码如下:
server.go是项目的入口函数,接口写在其中的main函数中,注意要import Gin的库

import "gopkg.in/gin-gonic/gin.v1"
r.POST("/community/post/do", func(c *gin.Context) {
   topicId, _ := c.GetPostForm("topic_id")
   content, _ := c.GetPostForm("content")
   data := cotroller.PublishPost(topicId, content)
   c.JSON(200, data)
})

同时,在上述提到的三个层也添加对应代码:

Reposity

Reposity里面的db_init.go中添加一个变量:

var
{ rwMutex       sync.RWMutex }

由词猜意,这是Go语言定义的一个读写互斥锁,用于解决并发安全问题。

Service

service里面新增一个publish_post.go:

package service

import (
   "errors"
   "time"
   "unicode/utf16"

   "github.com/Moonlight-Zhao/go-project-example/repository"
   idworker "github.com/gitstliu/go-id-worker"
)

var idGen *idworker.IdWorker

func init() {
   idGen = &idworker.IdWorker{}
   idGen.InitIdWorker(1, 1)
}

func PublishPost(topicId int64, content string) (int64, error) {
   return NewPublishPostFlow(topicId, content).Do()
}

func NewPublishPostFlow(topicId int64, content string) *PublishPostFlow {
   return &PublishPostFlow{
      content: content,
      topicId: topicId,
   }
}

type PublishPostFlow struct {
   content string
   topicId int64

   postId int64
}

// 返回postId
func (f *PublishPostFlow) Do() (int64, error) {
   if err := f.checkParam(); err != nil {
      return 0, err
   }
   if err := f.publish(); err != nil {
      return 0, err
   }
   return f.postId, nil
}

// 限制帖子内容字数
func (f *PublishPostFlow) checkParam() error {
   if len(utf16.Encode([]rune(f.content))) >= 500 {
      return errors.New("content length must be less than 500")
   }
   return nil
}

// 调用下一层(Reposity)的InsertPost,实现发布功能
func (f *PublishPostFlow) publish() error {
   post := &repository.Post{
      ParentId:   f.topicId,
      Content:    f.content,
      CreateTime: time.Now().Unix(),
   }
   id, err := idGen.NextId()
   if err != nil {
      return err
   }
   post.Id = id
   if err := repository.NewPostDaoInstance().InsertPost(post); err != nil {
      return err
   }
   f.postId = post.Id
   return nil
}
  • 项目要求生成的id唯一,参考代码使用开源项目"github.com/gitstliu/go-id-worker" 来完成这一功能。

image.png
示例代码的意思应该是:初始值为1000,每次递增1。
换成本项目中,于是变成了从 1开始,每次递增1。

cotroller里面新增一个publish_post.go:

package cotroller

import (
   "github.com/Moonlight-Zhao/go-project-example/service"
   "strconv"
)

func PublishPost(topicIdStr, content string) *PageData {
   //参数转换
   topicId, _ := strconv.ParseInt(topicIdStr, 10, 64)
   //获取service层结果
   postId, err := service.PublishPost(topicId, content)
   if err != nil {
      return &PageData{
         Code: -1,
         Msg:  err.Error(),
      }
   }
   return &PageData{
      Code: 0,
      Msg:  "success",
      Data: map[string]int64{
         "post_id": postId,
      },
   }
}

这里就是写接口的参数返回信息。

结语

至此,对该项目代码的学习就结束了。虽然我只是大概看懂了逻辑,对很多细节为什么要这么实现还不理解、对一些实现原理还是很懵,但是至少对如何用Go写项目有了一个初步的了解,还是非常有收获的。

至于我还未能理解的地方,等我再更深入地学习Go及其原理、应用之后再回过头看,应该会有新的体悟。

相关文章
|
12天前
|
存储 开发工具 数据库
认证源码分析与自定义后端认证逻辑
认证源码分析与自定义后端认证逻辑
23 0
认证源码分析与自定义后端认证逻辑
|
3月前
|
缓存 前端开发 中间件
[go 面试] 前端请求到后端API的中间件流程解析
[go 面试] 前端请求到后端API的中间件流程解析
Go语言的条件控制语句及循环语句的学习笔记
本文是Go语言的条件控制语句和循环语句的学习笔记,涵盖了if语句、if-else语句、if嵌套语句、switch语句、select语句以及for循环和相关循环控制语句的使用方法。
Go语言的条件控制语句及循环语句的学习笔记
|
2月前
|
IDE Java 开发工具
流操作代码开发后端逻辑
要开始使用魔笔平台开发,请先登录并下载代码模板。通过应用管理找到目标应用并进入设计器,下载最新的`bundle.zip`模板,解压缩后获得Java工程。注意不要修改核心目录内容,并遵循命名规则。开发环境需支持JDK11+与Maven3.5+。每个后端逻辑流操作会在`custom-action-core`模块中生成实现类,主要逻辑编写在`execute`方法中。利用`MobiContext`参数进行实体和结构体操作。更多细节请参照具体步骤说明。
32 3
|
2月前
|
IDE Java 开发工具
流操作代码开发后端逻辑
该文档指导开发者在魔笔平台上下载代码模板并进行自定义逻辑流操作开发。首先登录魔笔并下载`bundle.zip`模板,解压缩后获得一个包含`custom-action-core`模块的Java工程。核心模块已预置接口与实现类,开发者需在`execute`方法中编写业务逻辑。工程要求JDK11+及Maven3.5+环境,并提供IDEA调试建议。每个自定义操作对应一个实现类,`MobiContext`参数简化了实体与结构体操作。注意不要修改工程特定目录以外的内容以确保兼容性。
35 2
|
3月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
131 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
2月前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
3月前
|
JavaScript 前端开发 程序员
后端程序员的前端必备-jQuery核心学习笔记
后端程序员的前端必备-jQuery核心学习笔记
58 13
|
2月前
|
人工智能 算法 搜索推荐
Go学习笔记-代码调
近年来,人工智能技术飞速发展,Cody作为由Sourcegraph开发的一款AI驱动编码助手,应运而生。它不仅提供代码预测与补全,还能深度理解代码上下文,为开发者提供准确建议,提升编码效率和质量。Cody能识别潜在错误并提出修复建议,缩短调试时间,同时进行智能代码审查,帮助优化代码结构和风格。未来,随着AI技术进步,Cody将不断学习优化,成为开发者不可或缺的伙伴,推动编程领域的创新与发展。
33 0
|
3月前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID