清风徐来
Michael's Blog
Echo模版嵌套

一个基本的Echo项目

main.go

package main

import (
	"net/http"

	"github.com/labstack/echo"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World!")
	})
	e.Logger.Fatal(e.Start(":1323"))
}

返回一个JSON响应

package main

import (
	"net/http"

	"github.com/labstack/echo"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World!")
	})

	e.GET("/json", func(c echo.Context) error {
		return c.JSONBlob(
			http.StatusOK,
			[]byte(`{"id": "1", "msg": "Hello, China!"}`),
		)
	})

	e.Logger.Fatal(e.Start(":1323"))
}

返回HTML

package main

import (
	"net/http"

	"github.com/labstack/echo"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World!")
	})

	e.GET("/json", func(c echo.Context) error {
		return c.JSONBlob(
			http.StatusOK,
			[]byte(`{"id": "1", "msg": "Hello, China!"}`),
		)
	})

	e.GET("/html", func(c echo.Context) error {
		return c.HTML(
			http.StatusOK,
			"<h1>Hello, Suzhou!</h1>",
		)
	})

	e.Logger.Fatal(e.Start(":1323"))
}

使用模板引擎呈现HTML

这次有点不一样,多个文件了,目录结构如下:

➜  golang-echo-template-example tree
.
├── handler
│   └── home_handler.go
├── main.go
└── view
    └── home.html

main.go

package main

import (
	"io"
	"html/template"

	"github.com/kissjava/golang-echo-template-example/handler"
	"github.com/labstack/echo"
)

// TemplateRegistry 定义模板注册表结构
type TemplateRegistry struct {
	templates *template.Template
}

// Render 实现 e.Renderer接口
func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
	e := echo.New()

	// 实例化一个模板注册表并在视图文件夹中注册所有html文件
	e.Renderer = &TemplateRegistry{
		templates: template.Must(template.ParseGlob("view/*.html")),
	}

	e.GET("/", handler.HomeHandler)

	e.Logger.Fatal(e.Start(":1323"))
}

handler/home_handler.go

package handler

import (
	"net/http"

	"github.com/labstack/echo"
)

// HomeHandler 根路径处理器函数
func HomeHandler(c echo.Context) error {
	// 第二个参数 home.html 是view/home.html中{{ define }}定义的名称
	return c.Render(http.StatusOK, "home.html", map[string]interface{}{
		"name": "HOME",
		"msg":  "Hello, World!",
	})
}

view/home.html

{{define "home.html"}}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kissjava Blog | {{index . "name"}}</title>
</head>
<body>
    <h1>{{index . "msg"}}</h1>
</body>
</html>
{{end}}

模版嵌套

在上面的设置中,HTML模板是一组完整的HTML代码。

如果是整个站点来使用,其中许多代码就是重复的。

使用嵌套模板使项目维护更加容易。

最初TemplateRegistry中的templates字段包含所有模板文件。

在新的设置中,我们将其设置为一个map字段,每一项都是针对特定HTML页面的一组模板文件。

新的项目结构如下:

➜  golang-echo-template-example tree
.
├── handler
│   ├── about__handler.go
│   └── home_handler.go
├── main.go
└── view
    ├── about.html
    ├── base.html
    └── home.html

main.go 如下:

package main

import (
	"errors"
	"io"
	"html/template"

	"github.com/kissjava/golang-echo-template-example/handler"
	"github.com/labstack/echo"
)

// TemplateRegistry 定义模板注册表结构
type TemplateRegistry struct {
	templates map[string]*template.Template
}

// Render 实现 e.Renderer接口
func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	tmpl, ok := t.templates[name]
	if !ok {
		err := errors.New("没有找到模版 -> " + name)
		return err
	}
	return tmpl.ExecuteTemplate(w, "base.html", data)
}

func main() {
	e := echo.New()

	//用模板集数组实例化一个模板注册表
	templates := make(map[string]*template.Template)
	templates["home.html"] = template.Must(template.ParseFiles("view/home.html", "view/base.html"))
	templates["about.html"] = template.Must(template.ParseFiles("view/about.html", "view/base.html"))
	e.Renderer = &TemplateRegistry{
		templates: templates,
	}

	e.GET("/", handler.HomeHandler)
	e.GET("/about", handler.AboutHandler)

	e.Logger.Fatal(e.Start(":1323"))
}

view/base.html

{{define "base.html"}}
  <!DOCTYPE html>
  <html>
    <head>
      <title>{{template "title" .}}</title>
    </head>
    <body>
      {{template "body" .}}
    </body>
  </html>
{{end}}

view/about.html

{{define "title"}}
  Kissjava Blog | {{index . "name"}}
{{end}}

{{define "body"}}
  <h1>{{index . "msg"}}</h1>
  <h2>This is the about page.</h2>
{{end}}

handler/about_handler.go

package handler

import (
	"net/http"

	"github.com/labstack/echo"
)

// AboutHandler /about处理器
func AboutHandler(c echo.Context) error {

	// 请注意第二个参数“about.html”是模板名
	// 等于main.go中定义的TemplateRegistry数组中的一个键
	return c.Render(http.StatusOK, "about.html", map[string]interface{}{
		"name": "About",
		"msg":  "All about kissjava!",
	})
}

结束

前面故意没有去改动home.html,可以参考 about.hmtl去比较实现。

{{define "title"}}
  Kissjava Blog | {{index . "name"}}
{{end}}

{{define "body"}}
  <h1>{{index . "msg"}}</h1>
  <h2>This is the home page.</h2>
{{end}}


最后修改于 2020-06-27