2SOMEone | Go-Zero后端框架

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

🔗Link

总结

Go-Zero框架的引入,使得2SOMEone的后端开发更加高效,减少了重复开发,让我们更关注到业务设计与逻辑代码实现上。