模板引擎配置 #

一、模板引擎概述 #

Echo支持多种模板引擎,可以根据项目需求选择合适的引擎。

1.1 支持的模板引擎 #

引擎 说明
Go Template Go标准库模板
Pongo2 Django风格模板
Jet 高性能模板引擎
Ace 简洁的模板引擎
Amber Jade风格模板
Handlebars Handlebars模板
Mustache Mustache模板

1.2 模板引擎接口 #

go
type Renderer interface {
    Render(w io.Writer, name string, data interface{}, c Context) error
}

二、Go标准模板 #

2.1 基本配置 #

go
package main

import (
    "html/template"
    "net/http"
    "github.com/labstack/echo/v4"
)

type Template struct {
    templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
    e := echo.New()
    
    t := &Template{
        templates: template.Must(template.ParseGlob("views/*.html")),
    }
    e.Renderer = t
    
    e.GET("/", func(c echo.Context) error {
        return c.Render(http.StatusOK, "index.html", map[string]interface{}{
            "title": "首页",
            "name":  "张三",
        })
    })
    
    e.Start(":8080")
}

2.2 模板文件 #

views/index.html

html
<!DOCTYPE html>
<html>
<head>
    <title>{{.title}}</title>
</head>
<body>
    <h1>Hello, {{.name}}!</h1>
</body>
</html>

2.3 模板目录结构 #

text
views/
├── layouts/
│   └── base.html
├── partials/
│   ├── header.html
│   └── footer.html
├── pages/
│   ├── index.html
│   └── about.html
└── errors/
    ├── 404.html
    └── 500.html

2.4 模板继承 #

go
func main() {
    e := echo.New()
    
    t := &Template{
        templates: template.Must(template.ParseFiles(
            "views/layouts/base.html",
            "views/pages/index.html",
            "views/pages/about.html",
        )),
    }
    e.Renderer = t
    
    e.GET("/", func(c echo.Context) error {
        return c.Render(http.StatusOK, "base.html", map[string]interface{}{
            "title":   "首页",
            "content": "index.html",
        })
    })
    
    e.Start(":8080")
}

views/layouts/base.html

html
<!DOCTYPE html>
<html>
<head>
    <title>{{.title}}</title>
</head>
<body>
    {{template "content" .}}
</body>
</html>

{{define "content"}}
{{template .content .}}
{{end}}

2.5 模板函数 #

go
func main() {
    e := echo.New()
    
    funcMap := template.FuncMap{
        "upper": strings.ToUpper,
        "lower": strings.ToLower,
        "title": strings.Title,
        "safe": func(s string) template.HTML {
            return template.HTML(s)
        },
    }
    
    t := &Template{
        templates: template.Must(template.New("").Funcs(funcMap).ParseGlob("views/*.html")),
    }
    e.Renderer = t
    
    e.Start(":8080")
}

模板中使用:

html
<p>{{upper .name}}</p>
<p>{{lower .name}}</p>
<p>{{safe "<strong>Bold</strong>"}}</p>

三、Pongo2模板 #

3.1 安装 #

bash
go get github.com/flosch/pongo2/v6

3.2 配置Pongo2 #

go
package main

import (
    "net/http"
    "github.com/flosch/pongo2/v6"
    "github.com/labstack/echo/v4"
)

type Pongo2Renderer struct {
    templateSet *pongo2.TemplateSet
}

func (r *Pongo2Renderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    var ctx pongo2.Context
    
    if data != nil {
        ctx = data.(pongo2.Context)
    }
    
    tmpl, err := r.templateSet.FromFile(name)
    if err != nil {
        return err
    }
    
    return tmpl.ExecuteWriter(ctx, w)
}

func main() {
    e := echo.New()
    
    e.Renderer = &Pongo2Renderer{
        templateSet: pongo2.NewFSLoader("views"),
    }
    
    e.GET("/", func(c echo.Context) error {
        return c.Render(http.StatusOK, "index.html", pongo2.Context{
            "title": "首页",
            "name":  "张三",
        })
    })
    
    e.Start(":8080")
}

3.3 Pongo2模板语法 #

html
<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
    
    {% if user %}
        <p>Welcome, {{ user.name }}!</p>
    {% endif %}
    
    {% for item in items %}
        <li>{{ item.name }}</li>
    {% endfor %}
    
    {% include "partials/header.html" %}
    
    {% extends "layouts/base.html" %}
    {% block content %}
        <p>Content here</p>
    {% endblock %}
</body>
</html>

四、Jet模板引擎 #

4.1 安装 #

bash
go get github.com/CloudyKit/jet/v6

4.2 配置Jet #

go
package main

import (
    "net/http"
    "github.com/CloudyKit/jet/v6"
    "github.com/labstack/echo/v4"
)

type JetRenderer struct {
    set *jet.Set
}

func (r *JetRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    tmpl, err := r.set.GetTemplate(name)
    if err != nil {
        return err
    }
    
    vars := make(jet.VarMap)
    
    return tmpl.Execute(w, vars, data)
}

func main() {
    e := echo.New()
    
    set := jet.NewSet(
        jet.NewOSFileSystemLoader("./views"),
        jet.InDevelopmentMode(),
    )
    
    e.Renderer = &JetRenderer{set: set}
    
    e.GET("/", func(c echo.Context) error {
        return c.Render(http.StatusOK, "index.jet", map[string]interface{}{
            "title": "首页",
            "name":  "张三",
        })
    })
    
    e.Start(":8080")
}

4.3 Jet模板语法 #

html
<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
    
    {% if user %}
        <p>Welcome, {{ user.name }}!</p>
    {% endif %}
    
    {% for item in items %}
        <li>{{ item.name }}</li>
    {% endfor %}
    
    {% extends "layouts/base.jet" %}
    {% block content %}
        <p>Content here</p>
    {% endblock %}
</body>
</html>

五、模板缓存 #

5.1 开发模式 #

go
func main() {
    e := echo.New()
    
    e.Debug = true
    
    var t *Template
    if e.Debug {
        t = &Template{
            templates: template.Must(template.ParseGlob("views/*.html")),
        }
    } else {
        t = &Template{
            templates: template.Must(template.ParseGlob("views/*.html")),
        }
    }
    e.Renderer = t
    
    e.Start(":8080")
}

5.2 热重载 #

go
type Template struct {
    templates *template.Template
    debug     bool
    files     []string
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    if t.debug {
        t.templates = template.Must(template.ParseFiles(t.files...))
    }
    return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
    e := echo.New()
    
    files := []string{
        "views/layouts/base.html",
        "views/pages/index.html",
    }
    
    t := &Template{
        templates: template.Must(template.ParseFiles(files...)),
        debug:     true,
        files:     files,
    }
    e.Renderer = t
    
    e.Start(":8080")
}

六、错误处理 #

6.1 模板错误处理 #

go
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    err := t.templates.ExecuteTemplate(w, name, data)
    if err != nil {
        log.Printf("Template error: %v", err)
        return echo.NewHTTPError(http.StatusInternalServerError, "模板渲染错误")
    }
    return nil
}

6.2 错误页面 #

go
e.HTTPErrorHandler = func(err error, c echo.Context) {
    code := http.StatusInternalServerError
    if he, ok := err.(*echo.HTTPError); ok {
        code = he.Code
    }
    
    errorPage := fmt.Sprintf("errors/%d.html", code)
    
    if err := c.Render(code, errorPage, map[string]interface{}{
        "code":    code,
        "message": err.Error(),
    }); err != nil {
        c.String(code, err.Error())
    }
}

七、完整示例 #

go
package main

import (
    "html/template"
    "io"
    "net/http"
    "strings"
    "github.com/labstack/echo/v4"
)

type Template struct {
    templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
    e := echo.New()
    
    funcMap := template.FuncMap{
        "upper": strings.ToUpper,
        "lower": strings.ToLower,
        "title": strings.Title,
        "safe": func(s string) template.HTML {
            return template.HTML(s)
        },
        "add": func(a, b int) int {
            return a + b
        },
    }
    
    t := &Template{
        templates: template.Must(template.New("").Funcs(funcMap).ParseGlob("views/*.html")),
    }
    e.Renderer = t
    
    e.GET("/", home)
    e.GET("/about", about)
    e.GET("/users", users)
    
    e.Logger.Fatal(e.Start(":8080"))
}

func home(c echo.Context) error {
    return c.Render(http.StatusOK, "index.html", map[string]interface{}{
        "title":   "首页",
        "message": "Welcome to Echo!",
    })
}

func about(c echo.Context) error {
    return c.Render(http.StatusOK, "about.html", map[string]interface{}{
        "title": "关于我们",
        "content": template.HTML(`
            <p>这是一个Echo框架示例项目。</p>
            <p>使用Go标准模板引擎。</p>
        `),
    })
}

func users(c echo.Context) error {
    users := []map[string]string{
        {"id": "1", "name": "张三", "email": "zhangsan@example.com"},
        {"id": "2", "name": "李四", "email": "lisi@example.com"},
        {"id": "3", "name": "王五", "email": "wangwu@example.com"},
    }
    
    return c.Render(http.StatusOK, "users.html", map[string]interface{}{
        "title": "用户列表",
        "users": users,
    })
}

views/index.html

html
<!DOCTYPE html>
<html>
<head>
    <title>{{.title}}</title>
</head>
<body>
    <h1>{{.message}}</h1>
    <p>Upper: {{upper .message}}</p>
    <p>Lower: {{lower .message}}</p>
    <nav>
        <a href="/">首页</a>
        <a href="/about">关于</a>
        <a href="/users">用户</a>
    </nav>
</body>
</html>

views/about.html

html
<!DOCTYPE html>
<html>
<head>
    <title>{{.title}}</title>
</head>
<body>
    <h1>{{.title}}</h1>
    {{.content}}
    <nav>
        <a href="/">首页</a>
        <a href="/about">关于</a>
        <a href="/users">用户</a>
    </nav>
</body>
</html>

views/users.html

html
<!DOCTYPE html>
<html>
<head>
    <title>{{.title}}</title>
</head>
<body>
    <h1>{{.title}}</h1>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Email</th>
            </tr>
        </thead>
        <tbody>
            {{range .users}}
            <tr>
                <td>{{.id}}</td>
                <td>{{.name}}</td>
                <td>{{.email}}</td>
            </tr>
            {{end}}
        </tbody>
    </table>
    <nav>
        <a href="/">首页</a>
        <a href="/about">关于</a>
        <a href="/users">用户</a>
    </nav>
</body>
</html>

八、总结 #

模板引擎配置要点:

要点 说明
Renderer接口 实现Render方法
Go Template 标准库模板
Pongo2 Django风格
Jet 高性能引擎
模板函数 FuncMap注册
模板缓存 生产环境启用

准备好学习模板渲染了吗?让我们进入下一章!

最后更新:2026-03-28