[ Go 框架三件套详解 | 青训营笔记 ]
这是我参与「第五届青训营」伴学笔记创作活动的第 5 天
零、前言:
新年快乐呀!啊过年摆了两天,这次的内容有点多,也踩了一些坑,希望能记录一下以后遇到了还能解决,结合文档与ppt写一份笔记,但是还是以文档为主,这里只是挑了一点常用的记录了一下。kitex还有很多没弄清楚回头到实际开发上的时候在补充吧。Gorm 的笔记也有根据金柱大佬的课(内部课)的,大佬真的好强
一、本堂课重点内容:
- Gorm
- Kitex
- Hertz
二、详细知识点介绍:
5.1 Gorm
GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
安装:go get -u gorm.io/gorm
以mysql为例:
-
数据库连接
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
DefaultStringSize: 256, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
}), &gorm.Config{})
-
结构体创建
type User struct { gorm.Model // 包含了ID和三个time Username string `gorm:"type:varchar(20);not null " json:"username" validate:"required,min=4,max=12" label:"用户名"` Password string `gorm:"type:varchar(500);not null" json:"password" validate:"required,min=6,max=120" label:"密码"` Role int `gorm:"type:int;DEFAULT:2" json:"role" validate:"required,gte=2" label:"角色码"` } -
自动迁移模式go
db.AutoMigrate(&User{}, &Product{}) // 创建User,Product表
当然也可以使用Migrator但是太麻烦了
-
增删改查
// 通过数据的指针来创建 db.Create(&user) // user可以是切片来实现批量插入 // 带额外条件的删除 db.Where("name = ?", "jinzhu").Delete(&email) // 条件更新 db.Model(&User{}).Where("active = ?", true).Update("name", "hello") // 获取第一条记录(主键升序) db.First(&user) db.Where("name = ?", "jinzhu").First(&user) // joins db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{}) // 分页获取 DB.Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&users).Error -
HOOK
Hook 是在创建、查询、更新、删除等操作之前、之后调用的函数
可以使用在比如说密码加密时,在创建密码之前调用一个加密函数
// 开始事务 BeforeSave BeforeCreate // 关联前的 save // 插入记录至 db // 关联后的 save AfterCreate AfterSave // 提交或回滚事务 func (u *User) BeforeCreate(tx *gorm.DB) (err error) { u.UUID = uuid.New() if !u.IsValid() { err = errors.New("can't save invalid data") } return }但是不这么命名好像是默认在创建之前(有懂的可以说一下)
5.1.5 what is IDL
idl 的文件有类似 proto,thrift 可以很明显的知道接口的入参,出参,函数名,可以用来进行RPC调用,也可以给kitex和hertz生成模板框架 (有一说一,居然还能这么搞,写gin都要自己生成文件)
5.2 Kitex
- 安装 kitex:
go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
安装 thriftgo:go install github.com/cloudwego/thriftgo@latest
使用IDL生成kitex框架
IDL:
namespace go echo
struct Request {
1: string Msg
}
struct Response {
1: string Msg
}
service EchoService {
Response Echo(1: Request req); // pingpong method
oneway void VisitOneway(1: Request req); // oneway method
}
生成代码:
# 若当前目录不在 $GOPATH/src 下,需要加上 -module 参数,一般为 go.mod 下的名字
kitex -module "your_module_name" -service a.b.c hello.thrift
这里 windows 系统应该是会发生(搜索不到文件?之类)的问题所以要用linux来生成,没有服务器或者懒得用vmware的可以用WSL,(106条消息) 史上最全的WSL安装教程_金士顿的博客-CSDN博客_wsl安装
出现WSL的问题可以看看这个 适用于 Linux 的 Windows 子系统文档 | Microsoft Learn
哎这个还是好麻烦希望以后能早早适配吧
结构:
.
└── kitex_gen
└── echo
├── echo.go
├── echoservice
│ ├── client.go
│ ├── echoservice.go
│ ├── invoker.go
│ └── server.go
└── k-echo.go
在server实现功能调用到client上
5.3 Hertz
-
安装
go install github.com/cloudwego/hertz/cmd/hz@latest- 在
GO111MODULE=on的情况下go install github.com/cloudwego/thriftgo@latest - 可以使用
hz new来生成测试代码
-
IDL 创建项目
// idl/hello.thrift
namespace go hello.example
struct HelloReq {
1: string Name (api.query="name"); // 添加 api 注解为方便进行参数绑定
}
struct HelloResp {
1: string RespBody;
}
service HelloService {
HelloResp HelloMethod(1: HelloReq request) (api.get="/hello");
}
service NewService {
HelloResp NewMethod(1: HelloReq request) (api.get="/new");
}
hz new --idl idl/hello.thrift --module "your_module_name"
注意这里要用管理员权限来执行这条命令,如果使用Goland来运行的话,可以在toolbox(或者其方式也可以),将Goland改为以管理员身份运行。同时,thrift 的路径要写对,否则还是会给你生成,生成的是 hz new 的那个pingpong框架。
-
项目结构及其含义
.
├── biz // business 层,存放业务逻辑相关流程
│ ├── handler // 存放 handler 文件
│ │ ├── hello // hello/example 对应 thrift idl 中定义的 namespace;而对于 protobuf idl,则是对应 go_package 的最后一级
│ │ │ └── example
│ │ │ ├── hello_service.go // handler 文件,用户在该文件里实现 IDL service 定义的方法,update 时会查找 当前文件已有的 handler 在尾部追加新的 handler
│ │ │ └── new_service.go // 同上,idl 中定义的每一个 service 对应一个文件
│ │ └── ping.go // 默认携带的 ping handler,用于生成代码快速调试,无其他特殊含义
│ ├── model // IDL 内容相关的生成代码
│ │ └── hello // hello/example 对应 thrift idl 中定义的 namespace;而对于 protobuf idl,则是对应 go_package
│ │ └── example
│ │ └── hello.go // thriftgo 的产物,包含 hello.thrift 定义的内容的 go 代码,update 时会重新生成
│ └── router // idl 中定义的路由相关生成代码
│ ├── hello // hello/example 对应 thrift idl 中定义的namespace;而对于 protobuf idl,则是对应 go_package 的最后一级
│ │ └── example
│ │ ├── hello.go // hz 为 hello.thrift 中定义的路由生成的路由注册代码;每次 update 相关 idl 会重新生成该文件
│ │ └── middleware.go // 默认中间件函数,hz 为每一个生成的路由组都默认加了一个中间件;update 时会查找当前文件已有的 middleware 在尾部追加新的 middleware
│ └── register.go // 调用注册每一个 idl 文件中的路由定义;当有新的 idl 加入,在更新的时候会自动插入其路由注册的调用;勿动
├── go.mod // go.mod 文件,如不在命令行指定,则默认使用相对于GOPATH的相对路径作为 module 名
├── idl // 用户定义的idl,位置可任意
│ └── hello.thrift
├── main.go // 程序入口
├── router.go // 用户自定义除 idl 外的路由方法
└── router_gen.go // hz 生成的路由注册代码,用于调用用户自定义的路由以及 hz 生成的路由
-
基本使用
-
路由
用法有点像gin,支持Restful风格的api接口与路由组的设计,路由的优先级:
静态路由>命名路由>通配路由Hertz 支持使用
:name这样的命名参数设置路由使用
*path这样的通配参数设置路由,并且通配参数会匹配所有内容。更多细节可以看文档路由 | CloudWeGo
-
-
Middleware
-
基本
// server 级别 h := server.Default() h.Use(GlobalMiddleware()) // 路由级别 group := h.Group("/group") group.Use(GroupMiddleware())如果有多个中间件按一定顺序执行时可以使用
.Next(ctx)实现 -
三个停止中间件的函数
Abort():终止后续调用AbortWithMsg(msg string, statusCode int):终止后续调用,并设置 response中body,和状态码AbortWithStatus(code int):终止后续调用,并设置状态码
-
常用中间件
CORS 跨源资源共享 | CloudWeGo
国际化 国际化 | CloudWeGo
-
-
参数绑定与校验
hertz 使用开源库 go-tagexpr 进行参数的绑定及验证,下面分别介绍参数绑定和参数验证的用法。
-
日志
哦哦这个支持zap,logrus这些常用的日志包,就不用自己写了
以zap为例:
go get github.com/hertz-contrib/logger/zap代码示例:
logger := hertzzap.NewLogger() hlog.SetLogger(logger) // .... hlog.Infof("hello %s", "hertz") -
服务注册与服务发现
-
服务发现
通过
server.WithRegistry指定自己的注册模块和自定义的注册信息。
-
h := server.Default(
server.WithHostPorts(addr),
server.WithRegistry(r, ®istry.Info{
ServiceName: "hertz.test.demo",
Addr: utils.NewNetAddr("tcp", addr),
Weight: 10,
Tags: nil,
}))
-
服务注册
通过使用 Hertz 提供的 Discovery 中间件,指定自定义的服务发现扩展。
三、总结:
这次东西挺多的,课程只是挑重点交了一下后面还需要很多时间自己看文档,特别是kitex还不是很懂,等写项目了再补充一下
四、参考资料:
5. 设计模式之 databasesql与 GORM实践.pdf - 飞书云文档 (feishu.cn)
Go 框架三件套详解.pptx - 飞书云文档 (feishu.cn)
GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.