模板引擎

目前 Macaron 应用有两款官方模板引擎中间件可供选择,即 macaron.Rendererpongo2.Pongoer

您可以自由选择使用哪一款模板引擎,并且您只能为一个 Macaron 实例 注册一款模板引擎。

共有特性:

  • 均支持 XML、JSON 和原始数据格式的响应,它们之间的不同只体现在 HTML 渲染上。
  • 均使用 templates 作为默认模板文件目录。
  • 均使用 .tmpl.html 作为默认模板文件后缀。
  • 均支持通过 Macaron 环境变量 来判断是否缓存模板文件(当 macaron.Env == macaron.PROD 时)。

渲染 HTML

Go 模板引擎

该服务可以通过函数 macaron.Renderer 来注入,并通过类型 macaron.Render 来体现。该服务为可选,一般情况下可直接使用 *macaron.Context.Render。该服务使用 Go 语言内置的模板引擎来渲染 HTML。如果想要了解更多有关使用方面的信息,请参见 官方文档

使用示例

假设您的应用拥有以下目录结构:

  1. main/
  2. |__ main.go
  3. |__ templates/
  4. |__ hello.tmpl

hello.tmpl:

  1. <h1>Hello {{.Name}}</h1>

main.go:

  1. package main
  2.  
  3. import "gopkg.in/macaron.v1"
  4.  
  5. func main() {
  6. m := macaron.Classic()
  7. m.Use(macaron.Renderer())
  8.  
  9. m.Get("/", func(ctx *macaron.Context) {
  10. ctx.Data["Name"] = "jeremy"
  11. ctx.HTML(200, "hello") // 200 为响应码
  12. })
  13.  
  14. m.Run()
  15. }

自定义选项

该服务允许接受一个参数来进行自定义选项(macaron.RenderOptions):

  1. package main
  2.  
  3. import "gopkg.in/macaron.v1"
  4.  
  5. func main() {
  6. m := macaron.Classic()
  7. m.Use(macaron.Renderer(macaron.RenderOptions{
  8. // 模板文件目录,默认为 "templates"
  9. Directory: "templates",
  10. // 模板文件后缀,默认为 [".tmpl", ".html"]
  11. Extensions: []string{".tmpl", ".html"},
  12. // 模板函数,默认为 []
  13. Funcs: []template.FuncMap{map[string]interface{}{
  14. "AppName": func() string {
  15. return "Macaron"
  16. },
  17. "AppVer": func() string {
  18. return "1.0.0"
  19. },
  20. }},
  21. // 模板语法分隔符,默认为 ["{{", "}}"]
  22. Delims: macaron.Delims{"{{", "}}"},
  23. // 追加的 Content-Type 头信息,默认为 "UTF-8"
  24. Charset: "UTF-8",
  25. // 渲染具有缩进格式的 JSON,默认为不缩进
  26. IndentJSON: true,
  27. // 渲染具有缩进格式的 XML,默认为不缩进
  28. IndentXML: true,
  29. // 渲染具有前缀的 JSON,默认为无前缀
  30. PrefixJSON: []byte("macaron"),
  31. // 渲染具有前缀的 XML,默认为无前缀
  32. PrefixXML: []byte("macaron"),
  33. // 允许输出格式为 XHTML 而不是 HTML,默认为 "text/html"
  34. HTMLContentType: "text/html",
  35. }))
  36. // ...
  37. }

Pongo2 模板引擎

该服务可以通过函数 pongo2.Pongoer 来注入,并通过类型 macaron.Render来体现。该服务为可选,一般情况下可直接使用 *macaron.Context.Render。该服务使用 Pongo2 v3 模板引擎来渲染 HTML。如果想要了解更多有关使用方面的信息,请参见 官方文档

使用示例

假设您的应用拥有以下目录结构:

  1. main/
  2. |__ main.go
  3. |__ templates/
  4. |__ hello.tmpl

hello.tmpl:

  1. <h1>Hello {{Name}}</h1>

main.go:

  1. package main
  2.  
  3. import (
  4. "github.com/go-macaron/pongo2"
  5. "gopkg.in/macaron.v1"
  6. )
  7.  
  8. func main() {
  9. m := macaron.Classic()
  10. m.Use(pongo2.Pongoer())
  11.  
  12. m.Get("/", func(ctx *macaron.Context) {
  13. ctx.Data["Name"] = "jeremy"
  14. ctx.HTML(200, "hello") // 200 is the response code.
  15. })
  16.  
  17. m.Run()
  18. }

自定义选项

该服务允许接受一个参数来进行自定义选项(pongo2.Options):

  1. package main
  2.  
  3. import (
  4. "github.com/go-macaron/pongo2"
  5. "gopkg.in/macaron.v1"
  6. )
  7.  
  8. func main() {
  9. m := macaron.Classic()
  10. m.Use(pongo2.Pongoer(pongo2.Options{
  11. // 模板文件目录,默认为 "templates"
  12. Directory: "templates",
  13. // 模板文件后缀,默认为 [".tmpl", ".html"]
  14. Extensions: []string{".tmpl", ".html"},
  15. // 追加的 Content-Type 头信息,默认为 "UTF-8"
  16. Charset: "UTF-8",
  17. // 渲染具有缩进格式的 JSON,默认为不缩进
  18. IndentJSON: true,
  19. // 渲染具有缩进格式的 XML,默认为不缩进
  20. IndentXML: true,
  21. // 允许输出格式为 XHTML 而不是 HTML,默认为 "text/html"
  22. HTMLContentType: "text/html",
  23. }))
  24. // ...
  25. }

模板集

当您的应用存在多套模板时,就需要使用模板集来实现运行时动态设置需要渲染的模板。

Go 模板引擎的使用方法:

  1. // ...
  2. m.Use(macaron.Renderers(macaron.RenderOptions{
  3. Directory: "templates/default",
  4. }, "theme1:templates/theme1", "theme2:templates/theme2"))
  5.  
  6. m.Get("/foobar", func(ctx *macaron.Context) {
  7. ctx.HTML(200, "hello")
  8. })
  9.  
  10. m.Get("/foobar1", func(ctx *macaron.Context) {
  11. ctx.HTMLSet(200, "theme1", "hello")
  12. })
  13.  
  14. m.Get("/foobar2", func(ctx *macaron.Context) {
  15. ctx.HTMLSet(200, "theme2", "hello")
  16. })
  17. // ...

Pongo2 模板引擎的使用方法:

  1. // ...
  2. m.Use(pongo2.Pongoers(pongo2.Options{
  3. Directory: "templates/default",
  4. }, "theme1:templates/theme1", "theme2:templates/theme2"))
  5.  
  6. m.Get("/foobar", func(ctx *macaron.Context) {
  7. ctx.HTML(200, "hello")
  8. })
  9.  
  10. m.Get("/foobar1", func(ctx *macaron.Context) {
  11. ctx.HTMLSet(200, "theme1", "hello")
  12. })
  13.  
  14. m.Get("/foobar2", func(ctx *macaron.Context) {
  15. ctx.HTMLSet(200, "theme2", "hello")
  16. })
  17. // ...

正如您所看到的那样,其实就是 2 个方法的不同:macaron.Rendererspongo2.Pongoers

第一个配置参数用于指定默认的模板集和配置选项,之后则是一个模板集名称和目录(通过 : 分隔)的列表。

如果您的模板集名称和模板集路径的最后一部分相同,则可以省略名称:

  1. // ...
  2. m.Use(macaron.Renderers(RenderOptions{
  3. Directory: "templates/default",
  4. }, "templates/theme1", "templates/theme2"))
  5.  
  6. m.Get("/foobar", func(ctx *macaron.Context) {
  7. ctx.HTML(200, "hello")
  8. })
  9.  
  10. m.Get("/foobar1", func(ctx *macaron.Context) {
  11. ctx.HTMLSet(200, "theme1", "hello")
  12. })
  13.  
  14. m.Get("/foobar2", func(ctx *macaron.Context) {
  15. ctx.HTMLSet(200, "theme2", "hello")
  16. })
  17. // ...

模板集辅助方法

检查某个模板集是否存在:

  1. // ...
  2. m.Get("/foobar", func(ctx *macaron.Context) {
  3. ok := ctx.HasTemplateSet("theme2")
  4. // ...
  5. })
  6. // ...

修改模板集的目录:

  1. // ...
  2. m.Get("/foobar", func(ctx *macaron.Context) {
  3. ctx.SetTemplatePath("theme2", "templates/new/theme2")
  4. // ...
  5. })
  6. // ...

小结

也许您已经发现,除了在 HTML 语法上的不同之外,两款引擎在代码层面的用法是完全一样的。

如果您只是想要得到 HTML 渲染后的结果,则可以调用方法 *macaron.Context.Render.HTMLString

  1. package main
  2.  
  3. import "gopkg.in/macaron.v1"
  4.  
  5. func main() {
  6. m := macaron.Classic()
  7. m.Use(macaron.Renderer())
  8.  
  9. m.Get("/", func(ctx *macaron.Context) {
  10. ctx.Data["Name"] = "jeremy"
  11. output, err := ctx.HTMLString("hello")
  12. // 进行其它操作
  13. })
  14.  
  15. m.Run()
  16. }

渲染 XML、JSON 和原始数据

相对于渲染 HTML 而言,渲染 XML、JSON 和原始数据的工作要简单的多。

  1. package main
  2.  
  3. import "gopkg.in/macaron.v1"
  4.  
  5. type Person struct {
  6. Name string
  7. Age int
  8. Sex string
  9. }
  10.  
  11. func main() {
  12. m := macaron.Classic()
  13. m.Use(macaron.Renderer())
  14.  
  15. m.Get("/xml", func(ctx *macaron.Context) {
  16. p := Person{"Unknwon", 21, "male"}
  17. ctx.XML(200, &p)
  18. })
  19. m.Get("/json", func(ctx *macaron.Context) {
  20. p := Person{"Unknwon", 21, "male"}
  21. ctx.JSON(200, &p)
  22. })
  23. m.Get("/raw", func(ctx *macaron.Context) {
  24. ctx.RawData(200, []byte("raw data goes here"))
  25. })
  26. m.Get("/text", func(ctx *macaron.Context) {
  27. ctx.PlainText(200, []byte("plain text goes here"))
  28. })
  29.  
  30. m.Run()
  31. }

响应状态码、错误和重定向

如果您希望响应指定状态码、错误和重定向操作,则可以参照以下代码:

  1. package main
  2.  
  3. import "gopkg.in/macaron.v1"
  4.  
  5. func main() {
  6. m := macaron.Classic()
  7. m.Use(macaron.Renderer())
  8.  
  9. m.Get("/status", func(ctx *macaron.Context) {
  10. ctx.Status(403)
  11. })
  12. m.Get("/error", func(ctx *macaron.Context) {
  13. ctx.Error(500, "Internal Server Error")
  14. })
  15. m.Get("/redirect", func(ctx *macaron.Context) {
  16. ctx.Redirect("/") // 第二个参数为响应码,默认为 302
  17. })
  18.  
  19. m.Run()
  20. }

运行时修改模板路径

如果您希望在运行时修改应用的模板路径,则可以调用方法 *macaron.Context.SetTemplatePath。需要注意的是,修改操作是全局生效的,而不只是针对当前请求。

使用示例

假设您的应用拥有以下目录结构:

  1. main/
  2. |__ main.go
  3. |__ templates/
  4. |__ hello.tmpl
  5. |__ templates2/
  6. |__ hello.tmpl

templates/hello.tmpl:

  1. <h1>Hello {{.Name}}</h1>

templates2/hello.tmpl:

  1. <h1>What's up, {{.Name}}</h1>

main.go:

  1. package main
  2.  
  3. import "gopkg.in/macaron.v1"
  4.  
  5. func main() {
  6. m := macaron.Classic()
  7. m.Use(macaron.Renderer())
  8.  
  9. m.Get("/old", func(ctx *macaron.Context) {
  10. ctx.Data["Name"] = "Unknwon"
  11. ctx.HTML(200, "hello")
  12. // 空字符串表示操作默认模板集
  13. ctx.SetTemplatePath("", "templates2")
  14. })
  15. m.Get("/new", func(ctx *macaron.Context) {
  16. ctx.Data["Name"] = "Unknwon"
  17. ctx.HTML(200, "hello")
  18. })
  19.  
  20. m.Run()
  21. }

当您首次请求 /old 页面时,响应结果为 <h1>Hello Unknwon</h1>,然后便执行了修改模板路径为 template2。此时,当您请求 /new 页面时,响应结果会变成 <h1>What's up, Unknwon</h1>