golang微服务框架中如何扩展go-zero使之支持html模板解析自动化
golang微服务框架中如何扩展go-zero使之支持html模板解析自动化
本篇文章为大家展示了golang微服务框架中如何扩展go-zero使之支持html模板解析自动化,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
go-zero本身支持html模板解析,我们只需要添加url对应模板解hanlder,实现逻辑就可以了
但是winlion太懒了,我甚至想
不写任何一个和模板相关的handler
如果有新的模板,直接把模板到某个特定目录就好,不要动任何go代码
在开发环境下没有缓存,修改了模板文件无需重启
需求在这里,开撸吧
在代码开始前,你可能需要阅读
金光灿灿的Gorm V2+适合创业的golang微服务框架go-zero实战 如果对go-zero已经了解,直接跳过吧
创建项目
生成go.mod文件
以如下指令创建项目
mkdirhtmlcdhtmlgomodinithtml
定义html.api
本文设计API如下 |描述|格式|方法|参数|返回|是否需要鉴权| |----|----|----|----|----|----| |用户登录|/open/authorization|post|mobile:手机号,passwd:密码,code:图片验证码|id:用户ID,token:用户token|否|
根据以上描述,书写api的模板文件如下
type(UserOptReqstruct{mobilestring`form:"mobile"`passwdstring`form:"passwd"`codestring`form:"code,optional"`}UserOptRespstruct{iduint`json:"id"`tokenstring`json:"token"`})servicehtml-api{@server(handler:authorizationHandlerfolder:open)post/open/authorization(UserOptReq)returns(UserOptResp)}
注意
本文和html模板相关,可以不适用goctl工具
但是由于使用工具可以为我们节省很多搭建框架相关的工作,所以建议使用用ctl生成
生成代码
采用如下指令生成代码
goctlapigo-apihtml.api-dir.
此时用go run html.go
指令可以发现系统以及运行
html模板自动解析实现思路
模板解析需要了解如下俩个已知知识点
html网页输出本质上是get请求输出
相对于一个项目来说,模板文件个数是有限的,因此我们可以将模板枚举出来,完成访模板名称和请求之间的映射
对于第一个,我们可以构建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应用配置funchtmlhandler(gloabtemplate*template.Template,tplnamestring,serverCtx*svc.ServiceContext)http.HandlerFunc{returnfunc(whttp.ResponseWriter,r*http.Request){//模板名字就是r.URL.Patht:=gloabtemplate//如果是调试模式,则支持热解析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和模板名称之间的映射关系
这里有几个点需要强调:
在golang中,每个包含模板内容的html文件会被解析成一个模板,如在
view/www/
下新建test.html
文件,即使里面没有内容,系统也会将其解析得到一个名叫test.html
的模板。如果在模板文件以template标签中定义名称为
www/test.html
的模板,则系统又会解析得到一个名叫www/test.html
的模板,此时存在俩个模板,一个名叫test.html
,一个名叫www/test.html
view/www/test.html
文件内容如下
{{define"www/test.html"}}<h2>这是模板www/test.html的内容</h2>{{end}}
因此我们可以取巧,将模板名称命名成需要建立映射关系的uri 比如外部通过http://127.0.0.1:8888/www/test.html
来访问,此时req.URI.path为/www/test.html
我们可以用这个作为模板名称
如何枚举模板
这里用到了ParseGlob
函数,这个函数本质上是对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|\---wwwindex.htmltest.html
则我们可以使用格式字符串 ./internal/view/**/*
来遍历并解析并解析模板,建立模板和uri之间的对应关系,核心代码如下
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.phptplname:=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)
如何在模板中使用函数
有时候我们需要在模板中使用函数,则需要用到函数映射功能,golang提供接口函数Funcs()
来注入,
假设我们需要在/www/version.html中查看系统版本,应该怎么做呢?
定义相关函数
//handlers\funcs.gopackagehandlerimport("html/template")//定义varfuncsMaptemplate.FuncMap=make(template.FuncMap)funcFuncMap()template.FuncMap{funcsMap["version"]=versionfuncsMap["hello"]=helloreturnfuncsMap}funcversion()string{//这个函数返回当前版本号0.0.1return"0.01"}funchello(strstring)string{//这个函数返回当前版本号0.0.1return"hello"+str}
应用可以通过 template.New("").Funcs(FuncMap())
来注入响应函数
定义模板文件 新建文件
view/www/version.html
,内容如下
{{define"www/version.html"}}<h2>当前版本号:{{version}}</h2><h2>这里测试带参数的函数:{{hello"word"}}</h2>{{end}}
无参数的函数展示 此时模板文件中通过
{{version}}
即可调用并显示版本号0.01有参数的函数 对应有参数的函数,按照参数顺序排列,中间用空格隔开
以上显示结果
当前版本号:0.01这里测试带参数的函数:helloword
如何模板嵌套
使用templete
指令进行嵌套
新建view/public/header.html
内容如下
<!--顶部菜单Start--><divclass="top-menu-wrapperindex-menu"><h2>这是Head</h2></div>
新建view/public/footer.html
内容如下
<!--顶部菜单Start--><divclass="top-menu-wrapperindex-menu"><h2>这是footer</h2></div>
新建view/www/index.html
文件,内容如下
<!DOCTYPEhtml><html><head></head><body>{{template"header.html".}}<divclass="content-box"data-spy="scroll"data-target=".section-scrollspy"><h2>这是Index的内容</h2></div>{{template"footer.html".}}</body></html>
此时编译后即可得到如下内容
这是Head 这是Index的内容 这是footer
如何在模板中使用变量
在模板中直接使用 首先需要将变量暴露到模板中,这里我们使用到了
ExecuteTemplate
函数,该函数第三个参数即可以在模板里面访问的参数,比如如下代码,则在模板中可以访问Query了
data:=r.URI.Queryerr:=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
系统返回结果
arga=[123]argb=[456]
在嵌套模板中使用
在嵌套模板中使用需要将对象传入,方式是在模板名后加一个.
,如下 新建view/www/embd.html
文件
{{define"www/embd.html"}}没加点:{{template"www/arg.html"}}=======加点:{{template"www/arg.html".}}{{end}}
结果如下
没加点:<h6>arga=</h6><h6>argb=</h6>=======加点:<h6>arga=[123]</h6><h6>argb=[456]</h6>
如何实现模板热更新
假设我们的应用支持开发模式和生产模式,在生产模式下,由于有性能考虑,系统不需要每次访问都解析模板。而在开发模式下,每个模板有所任何小的修改,我们都希望模板能自动更新,怎么实现这个功能呢? 方案很多,有文件监听方案,如github.com/fsnotify/fsnotify
监听模板目录,也有标记位方案,无论模板有没有变动,只要是开发模式,每次请求都重新加载模板并解析,gin
就是这种方案,本文也采用这种方案,核心代码如下
//模板名字就是r.URL.Patht:=gloabtemplate//如果是debug模式ifserverCtx.Config.Debug{//每次都重新解析t,_=template.New("").Funcs(FuncMap()).ParseGlob(serverCtx.Config.TemplatePattern)}err:=t.ExecuteTemplate(w,tplname,r.URL.Query())
如何设置首页
本质上是指定/
请求对应的模板,以及系统错误对应的模板
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等页面
目前可以实现业务逻辑层面的404定制,如httpx.Error方法可用404.html替代。 对于部分场景如访问一个不存在的url,则需要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|\---wwwarg.htmlembd.htmlfunc.htmlindex.htmltest.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)}
本文代码获取
关注公众号betaidea
输入html
即可获得html解析相关代码 关注公众号betaidea
输入jwt
即可获得gozero集成jwt-token相关代码 关注公众号betaidea
输入gozero
即可gozero入门代码
下一篇预告
目前貌似还没找到go-zero对static file支持的例子,类似gin
哪样做静态资源服务貌的例子,那么明天就写一个吧。 在go-zero的路由框架下寻找解决方案。 《用go-zero 支持文件服务》
广而告之
送福利了uniapp用户福音来啦! 历经数十万用户考验,我们的客服系统终于对外提供服务了。 你还在为商城接入客服烦恼吗?只需一行代码,即可接入啦!! 只需一行代码!!!!
/*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}}}
效果杠杠的
上述内容就是golang微服务框架中如何扩展go-zero使之支持html模板解析自动化,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注恰卡编程网行业资讯频道。
推荐阅读
-
css边框属性如何设置(html button如何设置圆角边框颜色)
htmlbutton如何设置圆角边框颜色?在HTML中把块的边框可以做成圆角需要利用css的border-radius属性。cs...
-
Golang中的nil和零值怎么声明
Golang中的nil和零值怎么声明这篇文章主要讲解了“Golan...
-
golang Gob怎么使用
-
golang切片长度与容量指的是什么
golang切片长度与容量指的是什么今天小编给大家分享一下gola...
-
golang循环遍历map的方式有哪些
-
golang如何添加list元素
-
golang包的特性有哪些
golang包的特性有哪些这篇文章主要介绍了golang包的特性有...
-
如何从 PHP 过渡到 Golang?
我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗...
-
golang web从入门到精通 获取请求头信息、GET(POST)请求参数
-
适合PHP转Golang的函数类库
近几年Golang越来越火了,很多之前写PHP的也开始投入到Golang的怀抱中,今天小编给大家推荐一个挺好用的适合php转go的...