模板引擎
原创Golang框架源码模板大约 2 分钟
模板引擎
分析
- 当请求打到后端服务器时,通过ServeHTTP找到匹配的路径和匹配的处理函数,
- 和之前的接口不同的是,并不是返回json等数据,而是需要找到页面并返回
- 也就是说分两步,找文件、返回
- 找文件我们在做动态路由的时候留了一个*的通配符,我们可以对匹配到这种的路径统一写一个处理函数来找文件
- 返回
net/http库已经实现了,直接用就行
静态文件统一处理函数
我们期望的是,请求/assets这个前缀的,统一去/static这个路径下找,即e.Static("/assets", "./static")
func (g *RGroup) Static(pre, root string) {
handler := g.createStaticHandler(pre, http.Dir(root))
urlPattern := path.Join(pre, "/*filepath")
g.Get(urlPattern, handler)
}
func (g *RGroup) createStaticHandler(pre string, fs http.FileSystem) HandleFunc {
absolutePath := path.Join(g.pre, pre)
fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
return func(c *Context) {
file := c.Param("filepath")
// Check if file exists and/or if we have permission to access it
if _, err := fs.Open(file); err != nil {
c.Status(http.StatusNotFound)
return
}
fileServer.ServeHTTP(c.Writer, c.Req)
}
}
静态文件测试
func main() {
r := lee.New()
//r.Static("/assets", "D:\\GoLandProjects\\wechatbot\\test\\static")
r.Static("/assets", "./static") // 使用相对路径必须在项目根目录下
r.Run(":8080")
}
动态渲染
这部分功能基本都是html.template提供的,直接使用就行
首先我们希望通过调用
e.LoadHTMLGlob("模板路径")来加载所有的模板文件func (e *Engine) LoadHTMLGlob(pattern string) { "返回一个html.template对象" = template.Must(template.New("").Funcs("需要一个参数处理函数的映射").ParseGlob(pattern)) }为了方便管理,我们将这个映射和template对象都挂到Engine上
type Engine struct { *RGroup router *router groups []*RGroup htmlTemplates *template.Template // for html render funcMap template.FuncMap // for html render } // 加载模板文件 func (e *Engine) LoadHTMLGlob(pattern string) { e.htmlTemplates = template.Must(template.New("").Funcs(e.funcMap).ParseGlob(pattern)) } // 设置处理函数 func (e *Engine) SetFuncMap(funcMap template.FuncMap) { e.funcMap = funcMap }返回我们封装一个
ctx.HTML方法,为了方便在context中拿到模板,添加一个Engine参数type Context struct { Writer http.ResponseWriter Req *http.Request StatusCode int Path string Method string Params map[string]string // middleware handlers []HandleFunc index int engine *Engine } func (ctx *Context) HTML(code int, name string, data interface{}) { ctx.SetHeader("Content-Type", "text/html") ctx.Status(code) if err := ctx.engine.htmlTemplates.ExecuteTemplate(ctx.Writer, name, data); err != nil { ctx.Fail(500, err.Error()) } } func (ctx *Context) Fail(code int, msg string) { ctx.Status(code) ctx.JSON(code, H{"message": msg}) }
动态渲染测试
- 大坑写在前面:我的文件名开头多了一个空格,根本看不出来,找了一下午
type student struct {
Name string
Age int8
}
func FormatAsDate(t time.Time) string {
year, month, day := t.Date()
return fmt.Sprintf("%d-%02d-%02d", year, month, day)
}
func main() {
r := lee.New()
r.Use(lee.Logger())
r.SetFuncMap(template.FuncMap{
"FormatAsDate": FormatAsDate,
})
r.LoadHTMLGlob("templates/*")
r.Static("/assets", "./static")
stu1 := &student{Name: "Geektutu", Age: 20}
stu2 := &student{Name: "Jack", Age: 22}
r.Get("/", func(c *lee.Context) {
c.HTML(http.StatusOK, "css.html", nil)
})
r.Get("/students", func(c *lee.Context) {
c.HTML(http.StatusOK, "arr.html", lee.H{
"title": "gee",
"stuArr": [2]*student{stu1, stu2},
})
})
r.Get("/date", func(c *lee.Context) {
c.HTML(http.StatusOK, "custom_func.tmpl", lee.H{
"title": "gee",
"now": time.Date(2019, 8, 17, 0, 0, 0, 0, time.UTC),
})
})
r.Run(":8080")
}
