Gin项目的设计与分层 | 青训营笔记

1,165 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

Gin项目的设计与分层

Gin框架非常的快速和高效

但是笔者使用的是springboot框架

springboot的分层非常的明显和直接

所以笔者思考用gin框架分层

设计

三层MCV结构

参考文献

基于Gin+Gorm框架搭建MVC模式的Go语言企业级后端系统 - 掘金 (juejin.cn)

首先,导入依赖

// 引入gin框架
require (
   github.com/gin-contrib/sse v0.1.0 // indirect
   github.com/gin-gonic/gin v1.8.2
   github.com/go-playground/locales v0.14.1 // indirect
   github.com/go-playground/universal-translator v0.18.0 // indirect
   github.com/go-playground/validator/v10 v10.11.1 // indirect
   github.com/goccy/go-json v0.10.0 // indirect
   github.com/json-iterator/go v1.1.12 // indirect
   github.com/leodido/go-urn v1.2.1 // indirect
   github.com/mattn/go-isatty v0.0.17 // indirect
   github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
   github.com/modern-go/reflect2 v1.0.2 // indirect
   github.com/pelletier/go-toml/v2 v2.0.6 // indirect
   github.com/ugorji/go/codec v1.2.8 // indirect
   golang.org/x/crypto v0.5.0 // indirect
   golang.org/x/net v0.5.0 // indirect
   golang.org/x/sys v0.4.0 // indirect
   golang.org/x/text v0.6.0 // indirect
   google.golang.org/protobuf v1.28.1 // indirect
   gopkg.in/yaml.v2 v2.4.0 // indirect
)

然后开始分层

首先我想到的是

controller层

经过学习,我查询到controller层可以用gin框架的路由代替

于是,再go文件夹下面建立route文件夹,然后创建route.go

开始初始化路由

apiRouter := r.Group("/douyin")
apiRouter.POST("/user/register/", controller.Register)
apiRouter.POST("/user/login/", controller.Login)
apiRouter.GET("/user/", jwt.VerifyToken, controller.UserInfo)
apiRouter.GET("/feed/", controller.VideoStream)
apiRouter.POST("/publish/action/", controller.VideoPublish)
apiRouter.GET("/publish/list/", controller.VideoList)

就像这样的情况,这样的不同的url请求就会定向到了controller的函数中去

然后再go的文件夹下再出创建service层

service层

接受controller的处理,同时用于返回错误信息

image-20230126214145947

比如上图所示

这里用于xxxservice用于处理数据

image-20230126220237705

就像这样的情况

用于处理contorler的参数,同时返回给上层的error,上层的err再开始处理

model层

model层用于定义数据模型

Gorm是全特性的ORM框架,即对象关系映射,这样,就需要类似Java那样建立与数据库映射的类,在Go语言当中,我们称之为结构体。

定义实体与sql模型的映射,同时定义curd接口,用于service层的调用。

// User 对应数据库User表结构的结构体
type User struct {
   Id       int64  //主键
   Name     string //昵称
   Password string //密码
}

同时sql语句如下

CREATE TABLE `users` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id,自增主键',
  `name` varchar(255) NOT NULL COMMENT '用户名',
  `password` varchar(255) NOT NULL COMMENT '用户密码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3 COMMENT='用户表';

这样就对应上来

踩坑点

由于不会jwt,所以耗尽大量的时候学习了golang的jwt框架的,所以研究jwt的时间比较长

这里定义了中间件用于jwt框架的颁发token和校验token

image-20230126221658721

如上图

同时再路由组添加相应的函数,用于校验token,如果token解析错误,那就直接返回false,和相应的json。

如果校验正确,直接进入下一步的next方法中

Config

这个层级用于定义相关的配置文件,比如数据库连接,redis的连接,一些相关的常数

// 初始化并返回数据链接
func Init() *gorm.DB {
   // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
   dsn := "root:zhang134679@tcp(127.0.0.1:3306)/tiktok?charset=utf8mb4&parseTime=True&loc=Local"
   //dsn := "tiktok:tiktok@tcp(47.115.218.216:3306)/tiktok?charset=utf8mb4&parseTime=True&loc=Local"
   Db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
      PrepareStmt: true, //缓存预编译语句
   })
   if err != nil {
      panic(err)
      return nil
   }
   println("连接成功")
   return Db
}

上述代码定义了数据库的连接

const Secret = "this_is_a_secret_key"

jwt的私钥

main

启动项目

func main()  {
   //连接数据库
   err :=dao.InitMySql()
   if err !=nil{
      panic(err)
   }
   //程序退出关闭数据库连接
   defer dao.Close()
   //绑定模型
   dao.SqlSession.AutoMigrate(&entity.User{})
   //注册路由
   r :=routes.SetRouter()
   //
   r.Run(":8080")
}

总结

gin也可以像springboot那样分层

只不过要自己定义的比较多

但是好在数据比较灵活