跳至主要內容

模板引擎

程序员李某某原创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")
}

上次编辑于:
贡献者: ext.liyuanhao3