7.7. template包
template包是GO标准库的一个部分。我们使用template将HTML存放在一个单独的文件中,可以更改编辑页面的布局而不用修改相关的GO代码。
首先,我们必须将template添加到导入列表:
import (
"http"
"io/ioutil"
"os"
"template"
)
创建一个包含HTML表单的模板文件。打开一个名为edit.html的新文件,添加下面的行:
<h1>Editing {title}</h1>
<form action="/save/{title}" method="POST">
<div><textarea name="body" rows="20" cols="80">{body|html}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>
修改editHandler,用模板替代硬编码的HTML。
func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
t, _ := template.ParseFile("edit.html", nil)
t.Execute(p, w)
}
函数template.ParseFile读取edit.html的内容,返回*template.Template类型的数据。
方法t.Execute用p.title和p.body的值替换模板中所有的{title}和{body},并且把结果写到http.Conn。
注意,在上面的模板中我们使用{body|html}。|html部分请求模板引擎在输出body的值之前,先将它传到html格式化器(formatter),转义HTML字符(比如用&aamp;gt;替换>)。 这样做,可以阻止用户数据破坏表单HTML。
既然我们删除了fmt.Sprintf语句,我们可以删除导入列表中的"fmt"。
使用模板技术,我们可以为viewHandler创建一个模板,命名为view.html。
<h1>{title}</h1>
<p>[<a href="/edit/{title}">edit</a>]</p>
<div>{body}</div>
修改viewHandler:
func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
t, _ := template.ParseFile("view.html", nil)
t.Execute(p, w)
}
注意,在两个处理函数(handler)中使用了几乎完全相同的模板处理代码,我们可以把模板处理代码写成一个单独的函数,以消除重复。
func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
renderTemplate(w, "view", p)
}
func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
renderTemplate(w, "edit", p)
}
func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
t, _ := template.ParseFile(tmpl+".html", nil)
t.Execute(p, w)
}
现在,处理函数(handler)代码更短、更加简单。