在本节,最终的代码目录结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| dain/ |--context.go |--dain.go |--logger.go |--router.go |--trie.go |--go.mod static/ |--css/ |--index.css templates/ |--index.tmpl main.go go.mod
|
实现目标
实现加载静态文件以及模板渲染功能:
main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package main
import ( "DawnGin/dain" "net/http" )
func main() { e := dain.New()
e.Use(dain.Logger())
e.Static("/static", "./static")
e.LoadHTMLGlob("templates/*")
e.Get("/index", func(c *dain.Context) { c.HTML(http.StatusOK, "index.tmpl", c.Path) })
e.Run(":9000") }
|
templates/index.tmpl
1 2 3 4
| <html> <link rel="stylesheet" href="/static/css/index.css"> <p>index.css is loaded, path is {{.}}</p> </html>
|
static/css/index.css
1 2 3 4 5
| p { color: orange; font-weight: 700; font-size: 20px; }
|
静态文件
dain/dain.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc { absolutePath := path.Join(group.prefix, relativePath) fileServer := http.StripPrefix(absolutePath, http.FileServer(fs)) return func(c *Context) { file := c.Param("filepath") if _, err := fs.Open(file); err != nil { c.Status(http.StatusNotFound) return } fileServer.ServeHTTP(c.Writer, c.Req) } }
func (group *RouterGroup) Static(relativePath string, root string) { handler := group.createStaticHandler(relativePath, http.Dir(root)) urlPattern := path.Join(relativePath, "/*filepath") group.Get(urlPattern, handler) }
|
模板渲染
Engine
dain/dain.go
修改 Engine 结构,添加用于记录模板的属性:
1 2 3 4 5 6 7 8 9 10 11
| type Engine struct { router *router *RouterGroup groups []*RouterGroup htmlTemplates *template.Template funcMap template.FuncMap }
|
增加两个方法,分别用于注册模板函数以及加载模板文件:
1 2 3 4 5 6 7
| func (e *Engine) SetFuncMap(funcMap template.FuncMap) { e.funcMap = funcMap }
func (e *Engine) LoadHTMLGlob(pattern string) { e.htmlTemplates = template.Must(template.New("").Funcs(e.funcMap).ParseGlob(pattern)) }
|
Context
dain/context.go
Context 结构体中增加指向引擎 Engine 的属性,用于访问模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| type Context struct { Writer http.ResponseWriter Req *http.Request Path string Method string Params map[string]string StatusCode int handlers []HandlerFunc index int engine *Engine }
|
同时,修改 c.HTML 方法,使之能够渲染模板:
1 2 3 4 5 6 7 8 9 10 11 12
| func (c *Context) Fail(code int, err string) { c.index = len(c.handlers) c.JSON(code, H{"msg": err}) }
func (c *Context) HTML(code int, name string, data interface{}) { c.SetHeader("Content-Type", "text/html") c.Status(code) if err := c.engine.htmlTemplates.ExecuteTemplate(c.Writer, name, data); err != nil { c.Fail(http.StatusInternalServerError, err.Error()) } }
|
dain/dain.go
因为在 Context 中增加了指向 Engine 的字段,所以需要在 ServeHTTP 中对 c.engine 赋值:
1 2 3 4 5 6 7 8 9 10 11
| func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) { c := NewContext(w, r) for _, group := range e.groups { if strings.HasPrefix(r.URL.Path, group.prefix) { c.handlers = append(c.handlers, group.middleware...) } } c.engine = e e.router.handle(c) }
|