7.4 模板处理

什么是模板

你一定听说过一种叫做MVC的设计模式,Model处理数据,View展现结果,Controller控制用户的请求,至于View层的处理,在很多动态语言里面都是通过在静态HTML中插入动态语言生成的数据,例如JSP中通过插入<%=....=%>,PHP中通过插入<?php.....?>来实现的。

通过下面这个图可以说明模板的机制

图7.1 模板机制图

Web应用反馈给客户端的信息中的大部分内容是静态的,不变的,而另外少部分是根据用户的请求来动态生成的,例如要显示用户的访问记录列表。用户之间只有记录数据是不同的,而列表的样式则是固定的,此时采用模板可以复用很多静态代码。

Go模板使用

在Go语言中,我们使用template包来进行模板处理,使用类似ParseParseFileExecute等方法从文件或者字符串加载模板,然后执行类似上面图片展示的模板的merge操作。请看下面的例子:

func handler(w http.ResponseWriter, r *http.Request) {
    t := template.New("some template") //创建一个模板
    t, _ = t.ParseFiles("tmpl/welcome.html", nil)  //解析模板文件
    user := GetUser() //获取当前用户信息
    t.Execute(w, user)  //执行模板的merger操作
}

通过上面的例子我们可以看到Go语言的模板操作非常的简单方便,和其他语言的模板处理类似,都是先获取数据,然后渲染数据。

为了演示和测试代码的方便,我们在接下来的例子中采用如下格式的代码

模板中如何插入数据?

上面我们演示了如何解析并渲染模板,接下来让我们来更加详细的了解如何把数据渲染出来。一个模板都是应用在一个Go的对象之上,Go对象的字段如何插入到模板中呢?

字段操作

Go语言的模板通过{{}}来包含需要在渲染时被替换的字段,{{.}}表示当前的对象,这和Java或者C++中的this类似,如果要访问当前对象的字段通过{{.FieldName}},但是需要注意一点:这个字段必须是导出的(字段首字母必须是大写的),否则在渲染的时候就会报错,请看下面的这个例子:

package main

import (
    "html/template"
    "os"
)

type Person struct {
    UserName string
}

func main() {
    t := template.New("fieldname example")
    t, _ = t.Parse("hello {{.UserName}}!")
    p := Person{UserName: "Astaxie"}
    t.Execute(os.Stdout, p)
}

上面的代码我们可以正确的输出hello Astaxie,但是如果我们稍微修改一下代码,在模板中含有了未导出的字段,那么就会报错

type Person struct {
    UserName string
    email   string  //未导出的字段,首字母是小写的
}

t, _ = t.Parse("hello {{.UserName}}! {{.email}}")

上面的代码就会报错,因为我们调用了一个未导出的字段,但是如果我们调用了一个不存在的字段是不会报错的,而是输出为空。

如果模板中输出{{.}},这个一般应用与字符串对象,默认会调用fmt包输出字符串的内容。

输出嵌套字段内容

上面我们例子展示了如何针对一个对象的字段输出,那么如果字段里面还有对象,如何来循环的输出这些内容呢?我们可以使用{{with …}}…{{end}}{{range …}}{{end}}来进行数据的输出。