前言
上一章,我们学习了如何在框架中加入中间件,本章我们要实现解析模版,并且渲染数据到模板中
代码实现
原生代码实现文件服务器
- 使用
http.FileServer函数创建了一个文件服务器server,用于处理对静态文件的请求。这个文件服务器的根目录就是我们之前创建的dir对象。 - 使用
http.StripPrefix函数去除 URL 前缀,并将剩余的路径传递给文件服务器处理。例如,访问127.0.0.1:8181/static/a.txt文件服务器处理的就是a.txt这个文件
dir := http.Dir("./static")
server := http.FileServer(dir)
prefix := "/static"
http.Handle(prefix+"/", http.StripPrefix(prefix, server))
http.ListenAndServe(":8181", nil)
在框架中使用文件服务器加载文件
- 创建静态的Handler.这个方法主要是通过http.StripPrefix 用于创建一个带有前缀路径的处理器
- Static 静态文件服务
func (g *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandleFunc {
absolutePath := path.Join(g.prefix, relativePath)
server := http.StripPrefix(absolutePath, http.FileServer(fs))
return func(ctx *Context) {
file := ctx.Param("filepath")
if _, err := fs.Open(file); err != nil {
ctx.Status(http.StatusNotFound)
return
}
server.ServeHTTP(ctx.Writer, ctx.Req)
}
}
func (g *RouterGroup) Static(relativePath string, root string) {
handler := g.createStaticHandler(relativePath, http.Dir(root))
urlPatten := path.Join(relativePath, "*filepath")
g.GET(urlPatten, handler)
}
加载模版的方法
- html/template为 HTML 提供了较为完整的支持。包括普通变量渲染、列表渲染、对象渲染等。框架的模板渲染直接使用了
html/template提供的能力。
type Engine struct {
*RouterGroup
router *Router
groups []*RouterGroup
httpTemplate *template.Template //将所有的模版加载进内存
funcMap template.FuncMap //自定义模版渲染函数
}
//设置funcmap
func (e *Engine) SetFuncMap(funcMap template.FuncMap) {
e.funcMap = funcMap
}
//加载HTML模板
func (e *Engine) LoadHTMLGlob(patten string) {
e.httpTemplate = template.Must(template.New("").Funcs(e.funcMap).ParseGlob(patten))
}
修改Context和gee
- 修改HTML,加入
name参数可以便于找到需要执行的模版 - 修改ServeHTTP,给Context赋值engine
func (c *Context) HTML(code int, name string, data interface{}) {
c.Status(code)
c.SetHeader("Content-Type", "text/html")
if err := c.engine.httpTemplate.ExecuteTemplate(c.Writer, name, data); err != nil {
c.String(500, "服务器错误:%s", err.Error())
}
}
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var middlerwares []HandleFunc
for _, group := range e.groups {
if strings.HasPrefix(r.URL.Path, group.prefix) {
middlerwares = append(middlerwares, group.middleware...)
}
}
c := newContext(w, r)
c.handlers = middlerwares
c.engine = e
e.router.Handle(c)
}
文件架构/测试
func main() {
e := newEngine()
e.Static("/assets", "./static")
e.LoadHTMLGlob("template/*")
e.GET("/", func(ctx *Context) {
ctx.HTML(http.StatusOK, "b.tmpl", gee.H{
"Title": "gin从零开始",
"Body": "body",
})
})
e.Run(":7999")
}