golang微服务框架中如何扩展go-zero使之支持html模板解析自动化
本篇文章為大家展示了golang微服務框架中如何擴展go-zero使之支持html模板解析自動化,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
go-zero本身支持html模板解析,我們只需要添加url對應模板解hanlder,實現(xiàn)邏輯就可以了
但是winlion太懶了,我甚至想
-
不寫任何一個和模板相關(guān)的handler
-
如果有新的模板,直接把模板到某個特定目錄就好,不要動任何go代碼
-
在開發(fā)環(huán)境下沒有緩存,修改了模板文件無需重啟
需求在這里,開擼吧
在代碼開始前,你可能需要閱讀
金光燦燦的Gorm V2+適合創(chuàng)業(yè)的golang微服務框架go-zero實戰(zhàn) 如果對go-zero已經(jīng)了解,直接跳過吧
創(chuàng)建項目
生成go.mod文件
以如下指令創(chuàng)建項目
mkdirhtml cdhtml gomodinithtml
定義html.api
本文設計API如下 |描述|格式|方法|參數(shù)|返回|是否需要鑒權(quán)| |----|----|----|----|----|----| |用戶登錄|/open/authorization|post|mobile:手機號,passwd:密碼,code:圖片驗證碼|id:用戶ID,token:用戶token|否|
根據(jù)以上描述,書寫api的模板文件如下
type(
UserOptReqstruct{
mobilestring`form:"mobile"`
passwdstring`form:"passwd"`
codestring`form:"code,optional"`
}
UserOptRespstruct{
iduint`json:"id"`
tokenstring`json:"token"`
}
)
servicehtml-api{
@server(
handler:authorizationHandler
folder:open
)
post/open/authorization(UserOptReq)returns(UserOptResp)
}
注意
-
本文和html模板相關(guān),可以不適用goctl工具
-
但是由于使用工具可以為我們節(jié)省很多搭建框架相關(guān)的工作,所以建議使用用ctl生成
生成代碼
采用如下指令生成代碼
goctlapigo-apihtml.api-dir.
此時用go run html.go指令可以發(fā)現(xiàn)系統(tǒng)以及運行
html模板自動解析實現(xiàn)思路
模板解析需要了解如下倆個已知知識點
-
html網(wǎng)頁輸出本質(zhì)上是get請求輸出
-
相對于一個項目來說,模板文件個數(shù)是有限的,因此我們可以將模板枚舉出來,完成訪模板名稱和請求之間的映射
對于第一個,我們可以構(gòu)建get路由來實現(xiàn)請求,以首頁請求http://127.0.0.1:8888/index.html為例,核心代碼如下,
htmltplrouter:=rest.Route{
Method:http.MethodGet,
Path:"/index.html",
Handler:htmlhandler(...),
}
engine.AddRoute(htmltplrouter)
在上述代碼中,htmlhandler函數(shù)實現(xiàn)了對請求的響應,也就是解析了模板并將模板內(nèi)容輸出
//gloabtemplate:全局解析的模板參數(shù)
//tplname:模板名稱,
//serverCtx應用配置
funchtmlhandler(gloabtemplate*template.Template,tplnamestring,serverCtx*svc.ServiceContext)http.HandlerFunc{
returnfunc(whttp.ResponseWriter,r*http.Request){
//模板名字就是r.URL.Path
t:=gloabtemplate
//如果是調(diào)試模式,則支持熱解析
ifserverCtx.Config.Debug{
t,_=template.New("").Funcs(FuncMap()).ParseGlob(serverCtx.Config.TemplatePattern)
}
err:=t.ExecuteTemplate(w,tplname,r.URL.Query())
iferr!=nil{
httpx.Error(w,err)
}
}
}
如何建立uri和模板名稱之間的映射關(guān)系
這里有幾個點需要強調(diào):
-
在golang中,每個包含模板內(nèi)容的html文件會被解析成一個模板,如在
view/www/下新建test.html文件,即使里面沒有內(nèi)容,系統(tǒng)也會將其解析得到一個名叫test.html的模板。 -
如果在模板文件以template標簽中定義名稱為
www/test.html的模板,則系統(tǒng)又會解析得到一個名叫www/test.html的模板,此時存在倆個模板,一個名叫test.html,一個名叫www/test.html
view/www/test.html文件內(nèi)容如下
{{define"www/test.html"}}
<h2>這是模板www/test.html的內(nèi)容</h2>
{{end}}
因此我們可以取巧,將模板名稱命名成需要建立映射關(guān)系的uri 比如外部通過http://127.0.0.1:8888/www/test.html來訪問,此時req.URI.path為/www/test.html 我們可以用這個作為模板名稱
如何枚舉模板
這里用到了ParseGlob函數(shù),這個函數(shù)本質(zhì)上是對filepath.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/**/* 來遍歷并解析并解析模板,建立模板和uri之間的對應關(guān)系,核心代碼如下
gloabtemplate,err:=template.New("").Funcs(FuncMap()).ParseGlob("./internal/view/**/*")
//range輪詢
for_,tpl:=rangegloabtemplate.Templates(){
patern:=tpl.Name()
if!strings.HasPrefix(patern,"/"){
patern="/"+patern
}
//首頁默認index.htmlindex.htmindex.php
tplname:=tpl.Name()
if0==len(tplname){
tplname=serverCtx.Config.TemplateIndex
}
pageRouters=append(pageRouters,rest.Route{
Method:http.MethodGet,
Path:patern,
Handler:htmlhandler(gloabtemplate,tplname,serverCtx),
})
logx.Infof("registerpage%s%s",patern,tplname)
}
//添加到engin路由中
engine.AddRoutes(pageRouters)
如何在模板中使用函數(shù)
有時候我們需要在模板中使用函數(shù),則需要用到函數(shù)映射功能,golang提供接口函數(shù)Funcs()來注入,
假設我們需要在/www/version.html中查看系統(tǒng)版本,應該怎么做呢?
-
定義相關(guān)函數(shù)
//handlers\funcs.go
packagehandler
import(
"html/template"
)
//定義
varfuncsMaptemplate.FuncMap=make(template.FuncMap)
funcFuncMap()template.FuncMap{
funcsMap["version"]=version
funcsMap["hello"]=hello
returnfuncsMap
}
funcversion()string{
//這個函數(shù)返回當前版本號0.0.1
return"0.01"
}
funchello(strstring)string{
//這個函數(shù)返回當前版本號0.0.1
return"hello"+str
}
應用可以通過 template.New("").Funcs(FuncMap())來注入響應函數(shù)
-
定義模板文件 新建文件
view/www/version.html,內(nèi)容如下
{{define"www/version.html"}}
<h2>當前版本號:{{version}}</h2>
<h2>這里測試帶參數(shù)的函數(shù):{{hello"word"}}</h2>
{{end}}
-
無參數(shù)的函數(shù)展示 此時模板文件中通過
{{version}}即可調(diào)用并顯示版本號0.01 -
有參數(shù)的函數(shù) 對應有參數(shù)的函數(shù),按照參數(shù)順序排列,中間用空格隔開
-
以上顯示結(jié)果
當前版本號:0.01 這里測試帶參數(shù)的函數(shù):helloword
如何模板嵌套
使用templete指令進行嵌套
新建view/public/header.html內(nèi)容如下
<!--頂部菜單Start--> <divclass="top-menu-wrapperindex-menu"> <h2>這是Head</h2> </div>
新建view/public/footer.html內(nèi)容如下
<!--頂部菜單Start--> <divclass="top-menu-wrapperindex-menu"> <h2>這是footer</h2> </div>
新建view/www/index.html文件,內(nèi)容如下
<!DOCTYPEhtml>
<html>
<head></head>
<body>
{{template"header.html".}}
<divclass="content-box"data-spy="scroll"data-target=".section-scrollspy">
<h2>這是Index的內(nèi)容</h2>
</div>
{{template"footer.html".}}
</body>
</html>
此時編譯后即可得到如下內(nèi)容
這是Head 這是Index的內(nèi)容 這是footer
如何在模板中使用變量
-
在模板中直接使用 首先需要將變量暴露到模板中,這里我們使用到了
ExecuteTemplate函數(shù),該函數(shù)第三個參數(shù)即可以在模板里面訪問的參數(shù),比如如下代碼,則在模板中可以訪問Query了
data:=r.URI.Query err:=t.ExecuteTemplate(w,tplname,data)
新建view/www/arg.html文件
{{define"www/arg.html"}}
<h6>arga={{.arga}}</h6>
<h6>argb={{.argb}}</h6>
{{end}}
請求訪問方式http://127.0.0.1:8888/www/arg.html?arga=123&argb=456
系統(tǒng)返回結(jié)果
arga=[123] argb=[456]
-
在嵌套模板中使用
在嵌套模板中使用需要將對象傳入,方式是在模板名后加一個.,如下 新建view/www/embd.html文件
{{define"www/embd.html"}}
沒加點:{{template"www/arg.html"}}
=======
加點:{{template"www/arg.html".}}
{{end}}
結(jié)果如下
沒加點: <h6>arga=</h6> <h6>argb=</h6> ======= 加點: <h6>arga=[123]</h6> <h6>argb=[456]</h6>
如何實現(xiàn)模板熱更新
假設我們的應用支持開發(fā)模式和生產(chǎn)模式,在生產(chǎn)模式下,由于有性能考慮,系統(tǒng)不需要每次訪問都解析模板。而在開發(fā)模式下,每個模板有所任何小的修改,我們都希望模板能自動更新,怎么實現(xiàn)這個功能呢? 方案很多,有文件監(jiān)聽方案,如github.com/fsnotify/fsnotify監(jiān)聽模板目錄,也有標記位方案,無論模板有沒有變動,只要是開發(fā)模式,每次請求都重新加載模板并解析,gin就是這種方案,本文也采用這種方案,核心代碼如下
//模板名字就是r.URL.Path
t:=gloabtemplate
//如果是debug模式
ifserverCtx.Config.Debug{
//每次都重新解析
t,_=template.New("").Funcs(FuncMap()).ParseGlob(serverCtx.Config.TemplatePattern)
}
err:=t.ExecuteTemplate(w,tplname,r.URL.Query())
如何設置首頁
本質(zhì)上是指定/請求對應的模板,以及系統(tǒng)錯誤對應的模板
for_,tpl:=rangegloabtemplate.Templates(){
patern:=tpl.Name()
if!strings.HasPrefix(patern,"/"){
patern="/"+patern
}
//處理首頁邏輯
tplname:=tpl.Name()
if0==len(tplname){
//模板名稱為""那么就默認首頁吧
//恰好/對應的模板名稱為"",
tplname=serverCtx.Config.TemplateIndex
}
pageRouters=append(pageRouters,rest.Route{
Method:http.MethodGet,
Path:patern,
Handler:htmlhandler(gloabtemplate,tplname,serverCtx),
})
logx.Infof("registerpage%s%s",patern,tplname)
}
404等頁面
目前可以實現(xiàn)業(yè)務邏輯層面的404定制,如httpx.Error方法可用404.html替代。 對于部分場景如訪問一個不存在的url,則需要go-zero官方提供支持,并開發(fā)接口。
集成
以上操作完成后,我們得到如下項目目錄,
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中添加如下代碼段即可
funcRegisterHandlers(engine*rest.Server,serverCtx*svc.ServiceContext){
engine.AddRoutes([]rest.Route{
{
Method:http.MethodPost,
Path:"/open/authorization",
Handler:open.AuthorizationHandler(serverCtx),
},
})
//添加這個代碼段
RegisterHtmlHandlers(engine,serverCtx)
}
本文代碼獲取
關(guān)注公眾號betaidea 輸入html即可獲得html解析相關(guān)代碼 關(guān)注公眾號betaidea 輸入jwt即可獲得gozero集成jwt-token相關(guān)代碼 關(guān)注公眾號betaidea 輸入gozero即可gozero入門代碼
下一篇預告
目前貌似還沒找到go-zero對static file支持的例子,類似gin哪樣做靜態(tài)資源服務貌的例子,那么明天就寫一個吧。 在go-zero的路由框架下尋找解決方案。 《用go-zero 支持文件服務》
廣而告之
送福利了uniapp用戶福音來啦! 歷經(jīng)數(shù)十萬用戶考驗,我們的客服系統(tǒng)終于對外提供服務了。 你還在為商城接入客服煩惱嗎?只需一行代碼,即可接入啦!! 只需一行代碼!!!!
/*kefu.vue*/
<template>
<view>
<IdeaKefu:siteid="siteId"></IdeaKefu>
</view>
</template>
<script>
importIdeaKefufrom"@/components/idea-kefu/idea-kefu.vue"
exportdefault{
components:{
IdeaKefu
},
data(){
return{
siteId:2
}
}
}
效果杠杠的
總結(jié)
以上是生活随笔為你收集整理的golang微服务框架中如何扩展go-zero使之支持html模板解析自动化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么用计算机知道别人手机密码,怎样才能知
- 下一篇: 怎样用计算机命令修复软件,电脑修复指令是