如何在复杂业务场景中使用go-zero的goctl进行模板定制化,利用Go语言的text/template包生成高效易维护的代码
1. 介绍
在面对复杂且多样化的业务场景时,通过自定义模板可以生成高效且易于维护的代码。本节将介绍如何在 goctl
中使用 text/template
,并分享一些最佳实践。近期我们还将提供 goctl
模板参数规范,并在新版本中提供支持,以便更好地根据业务需求进行定制。
2. text/template
基础
2.1 定义模板
text/template
是 Go 语言标准库中的一个包,用于处理文本模板。模板使用双花括号 {{ }}
来表示动作。以下是一个简单的模板示例:
const tmpl = `Hello, {{.Name}}!`
2.2 解析和执行模板
我们可以使用 template.New
和 template.Parse
方法来解析模板,然后使用 Execute
方法来执行模板。
package main
import (
"os"
"text/template"
)
func main() {
const tmpl = `Hello, {{.Name}}!`
t, err := template.New("example").Parse(tmpl)
if err != nil {
panic(err)
}
data := map[string]string{
"Name": "World",
}
err = t.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
}
2.3 模板函数
text/template
允许我们通过 template.FuncMap
来注册自定义函数,扩展模板功能。
func ToUpper(s string) string {
return strings.ToUpper(s)
}
t.Funcs(template.FuncMap{
"ToUpper": ToUpper,
})
3. goctl
模板介绍
goctl
目前支持 api
、docker
、gateway
、kube
、model
、mongo
、newapi
和 rpc
指令的模板定制化。模板文件树结构如下:
.
├── api
│ ├── config.tpl
│ ├── context.tpl
│ ├── etc.tpl
│ ├── handler.tpl
│ ├── logic.tpl
│ ├── main.tpl
│ ├── middleware.tpl
│ ├── route-addition.tpl
│ ├── routes.tpl
│ ├── template.tpl
│ └── types.tpl
├── docker
│ └── docker.tpl
...
└── rpc
├── call.tpl
├── config.tpl
├── etc.tpl
├── logic-func.tpl
├── logic.tpl
├── main.tpl
├── server-func.tpl
├── server.tpl
├── svc.tpl
└── template.tpl
3.1 goctl
模板变量
在进行定制化之前,需要了解 goctl
内置的模板变量及其作用,模板变量参考官网介绍(go-zero 官方文档)。
3.2 模板定制化
实践 1:HTTP 生成 code-msg
响应格式
为了统一前端的数据格式解析,可以通过定制化模板实现 code-msg
响应格式。以下是修改后的模板示例:
package {{.PkgName}}
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
xhttp "github.com/zeromicro/x/http"
{{.ImportPackages}}
)
{{if .HasDoc}}{{.Doc}}{{end}}
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 {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
{{if .HasResp}}xhttp.JsonBaseResponseCtx(r.Context(), w, resp){{else}}xhttp.JsonBaseResponseCtx(r.Context(), w, nil){{end}}
}
}
}
实践 2:增加 model
分页查询
在 goctl
内置模板中没有集成分页查询功能。可以通过定制化模板来实现这一功能,具体实现可以参考 相关文档。
3.3 模板定制化的引用方法
模板定制化可以通过以下三种方式实现:
- 直接修改默认
goctl
模板目录中的模板 - 自定义模板目录
- 从 Git 仓库获取
具体操作步骤及优缺点详见上文内容。