2SOMEone | Go-Zero后端框架
by CUNOE, April 13, 2024
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/${goctl版本号}/api/handler.tpl
文件,可以通过模板初始化命令goctl template init进行初始化
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的后端开发更加高效,减少了重复开发,让我们更关注到业务设计与逻辑代码实现上。