go-zero本身支持html模板解析,我们只需要添加url对应模板解hanlder,实现逻辑就可以了
但是winlion太懒了,我甚至想- 不写任何一个和模板相关的handler
- 如果有新的模板,直接把模板到某个特定目录就好,不要动任何go代码
- 在开发环境下没有缓存,修改了模板文件无需重启
需求在这里,开撸吧
在代码开始前,你可能需要阅读 创建项目生成go.mod文件
以如下指令创建项目
mkdir html
cd html
go mod init html
复制代码
定义html.api
本文设计API如下 |描述|格式|方法|参数|返回|是否需要鉴权| |----|----|----|----|----|----| |用户登录|/open/authorization|post|mobile:手机号,passwd:密码,code:图片验证码|id:用户ID,token:用户token|否|
根据以上描述,书写api的模板文件如下
type (
UserOptReq struct {
mobile string `form:"mobile"`
passwd string `form:"passwd"`
code string `form:"code,optional"`
}
UserOptResp struct {
id uint `json:"id"`
token string `json:"token"`
}
)
service html-api {
@server(
handler: authorizationHandler
folder: open
)
post /open/authorization(UserOptReq) returns(UserOptResp)
}
复制代码
注意
- 本文和html模板相关,可以不适用goctl工具
- 但是由于使用工具可以为我们节省很多搭建框架相关的工作,所以建议使用用ctl生成
生成代码
采用如下指令生成代码
goctl api go -api html.api -dir .
复制代码
go run html.go
html模板自动解析实现思路
模板解析需要了解如下俩个已知知识点
- html网页输出本质上是get请求输出
- 相对于一个项目来说,模板文件个数是有限的,因此我们可以将模板枚举出来,完成访模板名称和请求之间的映射
http://127.0.0.1:8888/index.html
htmltplrouter:= rest.Route{
Method: http.MethodGet,
Path: "/index.html",
Handler: htmlhandler(...),
}
engine.AddRoute(htmltplrouter)
复制代码
htmlhandler
//gloabtemplate:全局解析的模板参数
//tplname:模板名称,
//serverCtx 应用配置
func htmlhandler(gloabtemplate *template.Template, tplname string, serverCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
//模板名字就是r.URL.Path
t := gloabtemplate
//如果是调试模式,则支持热解析
if serverCtx.Config.Debug {
t, _ = template.New("").Funcs(FuncMap()).ParseGlob(serverCtx.Config.TemplatePattern)
}
err := t.ExecuteTemplate(w, tplname, r.URL.Query())
if err != nil {
httpx.Error(w, err)
}
}
}
复制代码
如何建立uri和模板名称之间的映射关系
这里有几个点需要强调:
view/www/test.htmltest.htmlwww/test.htmlwww/test.htmltest.htmlwww/test.html
view/www/test.html
{{define "www/test.html"}}
<h1>这是模板www/test.html的内容</h1>
{{end}}
复制代码
http://127.0.0.1:8888/www/test.html/www/test.html
如何枚举模板
ParseGlobfilepath.ParseGlob()template.ParseFiles()internal\view
tree /F /A
| go.mod
| go.sum
| html.api
| html.go
| readme.md
|
+---etc
| html-api.yaml
|
\---internal
+---config
| config.go
|
+---handler
| | routes.go
| |
| \---open
| authorizationhandler.go
|
+---logic
| \---open
| authorizationlogic.go
|
+---svc
| servicecontext.go
|
+---types
| types.go
|
\---view
+---public
| footer.html
| header.html
|
\---www
index.html
test.html
复制代码
./internal/view/**/*
gloabtemplate,err:=template.New("").Funcs(FuncMap()).ParseGlob("./internal/view/**/*")
//range轮询
for _, tpl := range gloabtemplate.Templates() {
patern := tpl.Name()
if !strings.HasPrefix(patern, "/") {
patern = "/" + patern
}
//首页默认index.html index.htm index.php
tplname := tpl.Name()
if 0 == len(tplname) {
tplname = serverCtx.Config.TemplateIndex
}
pageRouters = append(pageRouters, rest.Route{
Method: http.MethodGet,
Path: patern,
Handler: htmlhandler(gloabtemplate, tplname, serverCtx),
})
logx.Infof("register page %s %s", patern, tplname)
}
//添加到engin路由中
engine.AddRoutes(pageRouters)
复制代码
如何在模板中使用函数
Funcs()
假设我们需要在/www/version.html中查看系统版本,应该怎么做呢?
- 定义相关函数
//handlers\funcs.go
package handler
import (
"html/template"
)
//定义
var funcsMap template.FuncMap = make(template.FuncMap)
func FuncMap() template.FuncMap {
funcsMap["version"] = version
funcsMap["hello"] = hello
return funcsMap
}
func version() string {
//这个函数返回当前版本号0.0.1
return "0.01"
}
func hello(str string) string {
//这个函数返回当前版本号0.0.1
return "hello "+ str
}
复制代码
template.New("").Funcs(FuncMap())
view/www/version.html
{{define "www/version.html"}}
<h1>当前版本号:{{version}}</h1>
<h1>这里测试带参数的函数:{{hello "word"}}</h1>
{{end}}
复制代码
{{version}}
当前版本号:0.01
这里测试带参数的函数:hello word
复制代码
如何模板嵌套
templete
view/public/header.html
<!-- 顶部菜单 Start -->
<div class="top-menu-wrapper index-menu">
<h1>这是Head</h1>
</div>
复制代码
view/public/footer.html
<!-- 顶部菜单 Start -->
<div class="top-menu-wrapper index-menu">
<h1>这是footer</h1>
</div>
复制代码
view/www/index.html
<!DOCTYPE html>
<html>
<head></head>
<body>
{{template "header.html" .}}
<div class="content-box" data-spy="scroll" data-target=".section-scrollspy">
<h1>这是Index的内容</h1>
</div>
{{template "footer.html" .}}
</body>
</html>
复制代码
此时编译后即可得到如下内容
这是Head 这是Index的内容 这是footer
如何在模板中使用变量
ExecuteTemplate
data := r.URI.Query
err := t.ExecuteTemplate(w, tplname, data)
复制代码
view/www/arg.html
{{define "www/arg.html"}}
<h5>arga={{.arga}}</h5>
<h5>argb={{.argb}}</h5>
{{end}}
复制代码
http://127.0.0.1:8888/www/arg.html?arga=123&argb=456
系统返回结果
arga=[123]
argb=[456]
复制代码
- 在嵌套模板中使用
.view/www/embd.html
{{define "www/embd.html"}}
没加点:{{template "www/arg.html"}}
=======
加点:{{template "www/arg.html" .}}
{{end}}
复制代码
结果如下
没加点:
<h5>arga=</h5>
<h5>argb=</h5>
=======
加点:
<h5>arga=[123]</h5>
<h5>argb=[456]</h5>
复制代码
如何实现模板热更新
github.com/fsnotify/fsnotifygin
//模板名字就是r.URL.Path
t := gloabtemplate
//如果是debug模式
if serverCtx.Config.Debug {
//每次都重新解析
t, _ = template.New("").Funcs(FuncMap()).ParseGlob(serverCtx.Config.TemplatePattern)
}
err := t.ExecuteTemplate(w, tplname, r.URL.Query())
复制代码
如何设置首页
/
for _, tpl := range gloabtemplate.Templates() {
patern := tpl.Name()
if !strings.HasPrefix(patern, "/") {
patern = "/" + patern
}
//处理首页逻辑
tplname := tpl.Name()
if 0 == len(tplname) {
//模板名称为""那么就默认首页吧
//恰好/对应的模板名称为"",
tplname = serverCtx.Config.TemplateIndex
}
pageRouters = append(pageRouters, rest.Route{
Method: http.MethodGet,
Path: patern,
Handler: htmlhandler(gloabtemplate, tplname, serverCtx),
})
logx.Infof("register page %s %s", patern, tplname)
}
复制代码
404等页面
go-zero
集成
以上操作完成后,我们得到如下项目目录,
tree /F /A
| go.mod
| go.sum
| html.api
| html.go
| readme.md
|
+---etc
| html-api.yaml
|
\---internal
+---config
| config.go
|
+---handler
| | funcs.go
| | html.go
| | routes.go
| |
| \---open
| authorizationhandler.go
|
+---logic
| \---open
| authorizationlogic.go
|
+---svc
| servicecontext.go
|
+---types
| types.go
|
\---view
+---public
| 404.html
| footer.html
| header.html
|
\---www
arg.html
embd.html
func.html
index.html
test.html
复制代码
routes.go
func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
engine.AddRoutes([]rest.Route{
{
Method: http.MethodPost,
Path: "/open/authorization",
Handler: open.AuthorizationHandler(serverCtx),
},
})
//添加这个代码段
RegisterHtmlHandlers(engine, serverCtx)
}
复制代码
本文代码获取
betaideahtmlbetaideajwtbetaideagozero
下一篇预告
gin
广而告之
送福利了uniapp用户福音来啦! 历经数十万用户考验,我们的客服系统终于对外提供服务了。 你还在为商城接入客服烦恼吗?只需一行代码,即可接入啦!! 只需一行代码!!!!
/*kefu.vue*/
<template>
<view>
<IdeaKefu :siteid="siteId" ></IdeaKefu>
</view>
</template>
<script> import IdeaKefu from "@/components/idea-kefu/idea-kefu.vue" export default { components:{ IdeaKefu }, data() { return { siteId:2 } } } 复制代码
效果杠杠的