开箱即用的go-zero(上) | 青训营

785 阅读4分钟

Go-zero 实战项目:blog

用户模块是后台管理系统常见的模块,它的功能大家也非常熟悉。管理用户涉及到前端操作,用户信息持久化又离不开数据库。所以用户模块可谓是 "麻雀虽小五脏俱全"。本文将详细介绍一下如何使用 go-zero 完成用户模块功能,如:用户登录、添加用户、删除用户、修改用户、查询用户,用户注册,用户登录,返回用户信息 等

本文主要是api网关层服务创建并且讲解。

image.png

最上面是 api 网关层。go-zero 需要 api 网关层来代理请求,把 request 通过 gRPC 转发给对应的 rpc 服务去处理。这块把具体请求转发到对应的 rpc 服务的业务逻辑,需要手写。

接下来是 rpc 服务层。上图 rpc 服务中的 user 就是接下来向大家演示的模块。每个 rpc 服务可以单独部署。服务启动后会把相关信息注册到 ETCD,这样 api 网关层就可以通过 ECTD 发现具体服务的地址。rpc 服务处理具体请求的业务逻辑,需要手写。

最后是Model 层。model 层封装的是数据库操作的相关逻辑。如果是查询类的相关操作,会先查询 redis 中是否有对应的缓存。非查询类操作,则会直接操作 MySQL。goctl 能通过 sql 文件生成普通的 CRDU 代码。上文也有提到,目前 goctl 这部分功能只支持 MySQL。

下面演示如何使用 go-zero 开发一个 blog 系统的用户模块。

api 网关层

编写 blog.api 文件

  • 生成 blog.api 文件

执行命令 goctl api -o blog.api,创建 blog.api 文件。

  • api 文件的作用

api 文件的详细语法请参阅文档[go-zero.dev/cn/api-gram…],本文按照个人理解谈一谈 api 文件的作用和基础语法。

api 文件是用来生成 api 网关层的相关代码的。

  • api 文件的语法

api 文件的语法和 Golang 语言非常类似,type 关键字用来定义结构体,service 部分用来定义 api 服务。

type 定义的结构体,主要是用来声明请求的入参和返回值的,即 request 和 response.

service 定义的 api 服务,则声明了路由,handler,request 和 response.

具体内容请结合下面的默认的生成的 api 文件进行理解

type (  
// 用户登录  
LoginRequest {  
Mobile string `json:"mobile"`  
Password string `json:"password"`  
}  
LoginResponse {  
AccessToken string `json:"accessToken"`  
AccessExpire int64 `json:"accessExpire"`  
}  
// 用户登录  
  
// 用户注册  
RegisterRequest {  
Name string `json:"name"`  
Gender int64 `json:"gender"`  
Mobile string `json:"mobile"`  
Password string `json:"password"`  
}  
RegisterResponse {  
Id int64 `json:"id"`  
Name string `json:"name"`  
Gender int64 `json:"gender"`  
Mobile string `json:"mobile"`  
}  
// 用户注册  
  
// 用户信息  
UserInfoResponse {  
Id int64 `json:"id"`  
Name string `json:"name"`  
Gender int64 `json:"gender"`  
Mobile string `json:"mobile"`  
}  
// 用户信息  
)  
  
service User {  
@handler Login  
post /api/user/login (LoginRequest) returns (LoginResponse)  
  
@handler Register  
post /api/user/register (RegisterRequest) returns (RegisterResponse)  
  
}  
  
@server(  
jwt: Auth  
)  
service User {  
@handler UserInfo  
post /api/user/userinfo () returns (UserInfoResponse)  
}
  • 编写 blog.api 文件

鉴于文章篇幅考虑完整的 blog.api 文件请参考 gitee 上的仓库。下面生成的代码是按照仓库上的 blog.api 文件生成的。

api 相关代码

  • 生成相关的代码

执行命令 goctl api go -api blog.api -dir . ,生成 api 相关代码。


├── blog.api # api 文件
├── blog.go # 程序入口文件
├── etc
│   └── blog-api.yaml # api 网关层配置文件
├── go.mod
├── go.sum
└── internal
    ├── config
    │   └── config.go # 配置文件
    ├── handler # 视图函数层, handler 文件与下面的 logic 文件一一对应
    │   ├── adduserhandler.go
    │   ├── deleteuserhandler.go
    │   ├── getusershandler.go
    │   ├── loginhandler.go
    │   ├── routes.go
    │   └── updateuserhandler.go
    ├── logic # 需要手动填充代码的地方
    │   ├── adduserlogic.go
    │   ├── deleteuserlogic.go
    │   ├── getuserslogic.go
    │   ├── loginlogic.go
    │   └── updateuserlogic.go
    ├── svc # 封装 rpc 对象的地方,后面会将
    │   └── servicecontext.go
    └── types # 把 blog.api 中定义的结构体映射为真正的 golang 结构体
        └── types.go

image.png

image.png

因为到此时还没涉及到 rpc 服务,所以 api 内各模块的调用关系就是非常简单的单体应用间的调用关系。routers.go 是路由,根据 request Method 和 url 把请求分发到对应到的 handler 上,handler 内部会去调用对应的 logic. logic 文件内是我们注入代码逻辑的地方。

小结

Api 层相关命令:

  • 执行命令 goctl api -o blog.api, 创建 blog.api 文件。
  • 执行命令 goctl api go -api blog.api -dir . ,生成 api 相关代码。
  • 加参数 goctl 也可以生成其他语言的 api 层的文件,比如 java、ts 等,尝试之后发现很难用,所以不展开了。