golang echo 代码详解之模版篇

在 echo 里使用模版则必须先注册一个,如果不注册就会报出下面这样的错误

{"time":"2017-12-12T23:03:57.939138716+08:00","level":"ERROR","prefix":"echo","file":"echo.go","line":"284","message":"Renderer not registered"}

注册就是给 echo.Renderer 赋值。

echo 的 Renderer 属性是一个接口

Renderer interface {
    Render(io.Writer, string, interface{}, Context) error
}

一、使用标准库模版

echo 的文档给出了使用官方模版注册的方式

// 实现 Renderer 接口
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)
}
// 处理 view 目录下的文件生成对应的模版
// 关于 ExecuteTemplate 和 ParseGlob 方法可以查看 
// https://wizardforcel.gitbooks.io/golang-stdlib-ref/content/67.html#Template.ExecuteTemplate
t := &Template{
    templates: template.Must(template.ParseGlob("public/views/*.html")),
}
// 赋值
e.Renderer = t

二、使用 pongo2

gopkg.in/flosch/pongo2.v3 是一个很不错的模版引擎,很多时候会选择它来渲染模版。

首先还是实现 Renderer 接口

type Template struct {
    // 这里使用一个 map 来存储预处理了的模版
    tmplMap map[string]*pongo2.Template
}

func (t *Template) Render(w io.Writer, templateName string, data interface{}, c echo.Context) error {
    // 这里根据传来的 name 从 tmplMap 里查找模版来渲染
      // 注意 ExcuteWriter 的参数必须是 map[string]interface{} 的
    dataMap := data.(map[string]interface{})
    template, exist := t.tmplMap[templateName]
    if !exist {
        return errors.New("template " + templateName + " not found")
    }
    return template.ExecuteWriter(dataMap, w)
}

然后预编译模版

// 读取目录下的文件预处理
func preCompile(dir string) *Template {
    tmplMap := make(map[string]*pongo2.Template)

    dirPath := filepath.Dir(dir)
    fileInfos, _ := ioutil.ReadDir(dirPath)

    for _, fileInfo := range fileInfos {
        t, err := pongo2.FromFile(path.Join(dir, fileInfo.Name()))
        if err != nil {
            log.Fatalf("\"%s\": %v", fileInfo.Name(), err)
        }
        tmplMap[strings.Replace(fileInfo.Name(), path.Ext(fileInfo.Name()), "", -1)] = t

    }

    return &Template{tmplMap}
}

最后赋值

func NewTemplates(dir string) *Template {
    return preCompile(dir)
}

t := NewTemplates("./views/")
e.Renderer = t

这样自定义的 renderer 就算完成了。