Go-Zero减少了重复开发,让程序员更关注到业务设计与逻辑代码实现上。
开发流程
前期准备
- goctl环境准备
- 新建工程
- 创建项目目录(可参考下方项目目录结构)
设计
- 数据库设计
- 业务设计
开发
API层
- 编写.api文件
- 代码生成
- 中间件实现
- Config添加RPC配置
- ServiceContext添加RPC
- 调用RPC接口实现相关逻辑
RPC层
- 编写.proto文件
- 代码生成
- Config添加数据库链接
- ServiceContext添加数据库交互类
- 调用数据库交互、完成数据处理
ORM数据库层
- 编写数据库结构表
- 编写数据库访问事务
Goctl 环境
GoctlVersion: 1.6.3 ProtocVersion: libprotoc 25.2 ProtocGenGoVersion: 1.33.0 ProtocGenGoGrpcVersion: 1.3.0
goctl是go-zero框架的代码生成工具,可以通过goctl生成API、RPC、Model等代码。
- 安装goctl
go install github.com/zeromicro/go-zero/tools/goctl@latest
- protoc 下载地址
https://github.com/protocolbuffers/protobuf/releases/tag/v25.2
安装protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.33.0
go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@1.3.0
项目结构参考
$ tree -d . ├── common // 存放全局通用的库 │ ├── ctxdata // 从context中获取信息 │ ├── util // 一些自定义的工具类 │ │ ├── xdb │ │ ├── xmath │ │ └── ...... │ ├── xerrors // 自定义错误处理 │ └── xtypes // 自定义类型 │ ├── ...... │ ├── xcode // 自定义错误码 │ └── xerr // 自定义错误类 ├── docker // Docker相关的配置文件存放于此 Dockerfile/docker-compose.yml 等 ├── etc // 所有API、RPC的配置文件存放于此 ├── flyio // Flyio 配置 ├── restful // 该文件夹下存放所有的API │ └── bubblebox │ ├── api_file // 存放该项目所有的API定义 │ │ ├── ...... │ │ └── user │ ├── etc │ └── internal │ ├── config │ ├── handler │ ├── logic // 业务逻辑 │ │ ├── userLogin │ │ ├── userNickname │ │ └── ...... │ ├── middleware // 中间件 │ ├── svc // 上下文 │ └── types ├── script // 脚本存放位置 ├── service // 各种Service存放位置 RPC/Store │ ├── ...... │ ├── oss │ └── user │ ├── core // 数据库表结构定义 │ ├── danmuauth-saas │ ├── rpc │ │ ├── etc │ │ ├── internal │ │ │ ├── config │ │ │ ├── logic // 业务逻辑 │ │ │ ├── server │ │ │ └── svc │ │ ├── pb │ │ │ └── user │ │ └── userservice │ └── store // 数据库交互 └── worker // 一些额外的 Worker └── guarder
开发实用脚本
生成API代码
#!/usr/bin/env bash # 合并API文件 ./script/merge_api_files.sh bubblebox.api # 生成API代码 goctl api format --dir ./restful/bubblebox/bubblebox.api goctl api go -api ./restful/bubblebox/bubblebox.api -dir ./restful/bubblebox -style gozero # 生成RPC代码 goctl rpc protoc ./service/post/rpc/post.proto --go_out=./service/post/rpc/pb --go-grpc_out=./service/post/rpc/pb --zrpc_out=./service/post/rpc goctl rpc protoc ./service/user/rpc/user.proto --go_out=./service/user/rpc/pb --go-grpc_out=./service/user/rpc/pb --zrpc_out=./service/user/rpc # 更多...
合并API文件
在项目体量较大时,我们可能会有很多的API文件,我们可以通过脚本将这些API文件合并成一个文件,然后通过goctl生成代码。
通过拆分api文件以避免出现一个文件上千行的代码的情况。
添加script/merge_api_files.sh
#!/usr/bin/env bash CRT_DIR=$(pwd) # 定义工作的路径 work_path="$CRT_DIR/restful/bubblebox" # 请修改为你的项目API路径 # 零散的 api 文件所在的目录 api_files_path="$work_path/api_file" # 定义输出文件路径 # output_file="bubblebox.api" # 第一步:从命令行参数中获取输出文件名 output_file="$1" # 第二步:检查是否提供了输出文件名 if [ -z "$output_file" ]; then echo "Usage: $0 <output_file>" exit 1 fi output_file="$work_path/$output_file" # 定义需要放在开头的文件 header_file="HEADER_INFO" header_file="$api_files_path/$header_file" # 第一步:检查 header 文件是否存在 if [ -f "$header_file" ]; then # 如果存在,首先将 header 文件的内容写入到输出文件中 cat "$header_file" > "$output_file" else # 如果 header 文件不存在,创建一个空的输出文件 > "$output_file" fi # 第二步:合并其他文件 # 使用 for 循环遍历目录下的所有 txt 文件 find "$api_files_path" -type f -name "*.api" | while read -r file; do # 跳过 header 文件,避免重复合并 if [ "$file" != "$header_file" ]; then # 添加一个空行到 output_file echo "" >> "$output_file" # 使用 >> 操作符将内容追加到 output_file cat "$file" >> "$output_file" fi # 检查文件最后一行是否为空行 last_line=$(tail -n 1 "$file") if [ -n "$last_line" ]; then # 如果最后一行不为空,添加一个空行 echo "" >> "$output_file" fi done goctl api format -dir $output_file
Goctl 模板
参考:https://go-zero.dev/docs/tutorials/customization/template
实现统一响应结构体
新建leaper-one/pkg
https/response/response.go
package response import ( "github.com/zeromicro/go-zero/rest/httpx" "net/http" ) type Body struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data"` } func Response(w http.ResponseWriter, resp interface{}, err error) { var body Body if err != nil { body.Code = -1 body.Msg = err.Error() } else { body.Code = 0 body.Msg = "success" body.Data = resp } httpx.OkJson(w, body) }
如果本地没有
文件,可以通过模板初始化命令goctl template init进行初始化 ~/.goctl/${goctl版本号}/api/handler.tpl
vim ~/.goctl/${goctl版本号}/api/handler.tpl
Windows则打开
C:\Users\{用户名}\.goctl\${goctl版本号}\api\handler.tpl
编辑为如下
package {{.PkgName}} import ( "net/http" "github.com/zeromicro/go-zero/rest/httpx" "github.com/leaper-one/pkg/https/response" {{.ImportPackages}} ) func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { {{if .HasRequest}}var req types.{{.RequestType}} if err := httpx.Parse(r, &req); err != nil { httpx.Error(w, err) return } {{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx) {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}}) {{if .HasResp}}response.Response(w, resp, err){{else}}response.Response(w, nil, err){{end}} } }
API IDL
总结
Go-Zero框架的引入,使得2SOMEone的后端开发更加高效,减少了重复开发,让我们更关注到业务设计与逻辑代码实现上。