这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
项目结构
hertz_gorm
├── biz
| ├── dal // Logic code that interacts with the database
│ ├── handler // Main logical code that handles HTTP requests
│ ├── hertz_gen // Scaffolding generated by hertz from idl files
| ├── model // Go struct corresponding to the database table
| ├── pack // Transformation between database model and response model
| ├── router // Middleware and mapping of routes to handlers
├── go.mod // go.mod
├── idl // thift idl
├── main.go // Initialize and start the server
├── router.go // Sample route registration
├── router_gen.go // Route registration
├── docker-compose.yml // docker-compose.yml
├── Makefile // Makefile
复制代码
这是整个项目的基本结构,非常的简洁,hz 为我们生成了大量的脚手架代码。
定义 IDL
hz是由Hertz框架提供的用于生成代码的工具。目前,hz可以基于 thrift 和 protobuf IDL为 Hertz 项目生成脚手架。
一个优秀的 IDL 文件的定义在使用 Hertz 开发中起着重要的作用,我们将使用thrift IDL作为这个项目的示例。
我们可以使用 api 注解让 hz 帮助我们进行参数绑定和验证,路由注册代码生成等。
hz 将根据以下api 注解生成 go tag,以便 Hertz 使用反射检索这些值并解析它们。
字段注解
Hertz 使用 go-tagexpr 开源库用于参数绑定和字段注释的校验,如下面的CreateUserRequest示例所示:
// api.thrift
struct CreateUserRequest{
1: string name (api.body="name", api.form="name",api.vd="(len($) > 0 && len($) < 100)")
2: Gender gender (api.body="gender", api.form="gender",api.vd="($ == 1||$ == 2)")
3: i64 age (api.body="age", api.form="age",api.vd="$>0")
4: string introduce (api.body="introduce", api.form="introduce",api.vd="(len($) > 0 && len($) < 1000)")
}
复制代码
form 注解允许 hz 自动为我们以 HTTP 请求体的形式绑定参数,省去了我们使用 PostForm 等方法手动绑定参数的麻烦。
vd 注解允许参数验证。例如,CreateUserRequest 使用 vd 注解来确保 gender 字段只有 1 或 2。
你可以参考 这里 了解更多关于参数验证语法的信息。
方法注解
方法注解可用于生成路由注册的代码。
// api.thrift
service UserService {
UpdateUserResponse UpdateUser(1:UpdateUserRequest req)(api.post="/v1/user/update/:user_id")
DeleteUserResponse DeleteUser(1:DeleteUserRequest req)(api.post="/v1/user/delete/:user_id")
QueryUserResponse QueryUser(1: QueryUserRequest req)(api.post="/v1/user/query/")
CreateUserResponse CreateUser(1:CreateUserRequest req)(api.post="/v1/user/create/")
}
复制代码
我们使用 POST 注解定义了 POST 方法和路由,hz 将根据定义的路由生成对应的路由组,Handler 框架以及中间件框架等。如biz/router/user_gorm/api.go 所示,以及 biz/handler/user_gorm/user_service.go。
我们也可以在idl文件中定义业务错误代码:
// api.thrift
enum Code {
Success = 1
ParamInvalid = 2
DBErr = 3
}
复制代码
hz 将基于这些为我们生成常量和相关方法:
// biz/hertz_gen/user_gorm/api.go
type Code int64
const (
Code_Success Code = 1
Code_ParamInvalid Code = 2
Code_DBErr Code = 3
)
复制代码
使用 hz 生成代码
在我们完成 IDL 的编写后,我们可以使用 hz 为我们生成脚手架代码。
执行下面的命令来生成代码:
hz new --model_dir biz/hertz_gen -mod github.com/cloudwego/hertz-examples/bizdemo/hertz_gorm -idl idl/api.thrift
复制代码
如果在第一次生成之后编辑了IDL,执行下面的命令来更新代码:
hz update --model_dir biz/hertz_gen -idl idl/api.thrift
复制代码
当然,项目已经为您生成了代码,因此您不需要执行它。当你实际使用 Hertz 进行 web 开发时,我相信你会发现它是一个非常有效和有趣的工具。
中间件的使用
在这个项目中,我们配置根路由组为所有路由使用 gzip 中间件以提高性能。
// biz/router/user_gorm/middleware.go
func rootMw() []app.HandlerFunc {
// your code...
// use gzip middleware
return []app.HandlerFunc{gzip.Gzip(gzip.DefaultCompression)}
}
复制代码
只需在生成的脚手架代码中添加一行代码,非常简单。你可以参考 hertz-contrib/gzip 以获取更多自定义配置的信息。
使用 Gorm 操作数据库
配置 Gorm
要在数据库中使用 GORM,你首先需要使用驱动程序连接数据库并配置 GORM,如 biz/dal/mysql/init.go 所示。
// biz/dal/mysql/user.go
package mysql
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var dsn = "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local"
var DB *gorm.DB
func Init() {
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
SkipDefaultTransaction: true,
PrepareStmt: true,
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
panic(err)
}
}
复制代码
这里我们通过 DSN 连接 MySQL 数据库,并维护一个全局数据库操作对象 DB。
在GORM配置方面,由于本项目不涉及同时操作多张表,我们可以将 SkipDefaultTransaction 配置为 true 来跳过默认事务,并通过PrepareStmt 启用缓存以提高效率。
我们还使用了默认的 logger,以便我们可以清楚地看到 GORM 为我们生成的 SQL。
转载作者:JustLorain
链接:juejin.cn/post/717991…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。