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)代码更短、更加简单。