0%

Go http模板

  • Go 模板引擎
  • 解析模板
  • 执行模板

模板简介

  • Web 模板就是预先设计好的 HTML 页面,它可以被模板引擎反复的使用,来产生 HTML 页面
  • Go 的标准库提供了 text/template,html/template 两个模板库
    • 大多数 Go 的 Web 框架都使用这些库作为 默认的模板引擎
  • 模板引擎可以合并模板与上下文数据,产生最终的 HTML

两种理想的模板引擎:

Go 模板引擎

  • Go 主要使用的是 text/template,HTML 相关的部分使用了 html/template,是个混合体。
  • 和大多数模板引擎一样,Go Web 的模板位于无逻辑和嵌入逻辑之间

Go 模板引擎的工作原理

  • 在 Web 应用中,通常是由 handler 来触发模板引擎
  • handler 调用模板引擎,并将使用的模板传递给引擎
    • 通常是一组模板文件和动态数据
  • 模板引擎生成 HTML,并将其写入到 ResponseWriter
  • ResponseWriter 再将它加入到 HTTP 响应中,返回给客户端

关于模板

  • 模板必须是可读的文本格式,扩展名任意。对于 Web 应用通常就是 HTML
  • text/template 是通用模板引擎,html/template 是 HTML 模板引擎
  • action 位于双层花括号之间:{{ . }}
    • 这里的 . 就是一个 action
    • 它可以命令模板引擎将其替换成一个值

使用模板引擎

  • 解析模板源(可以是字符串或模板文件),从而创建一个解析好的 模板的 struct ( template.Template )
  • 执行解析好的模板 ( t.Execute() ) ,并传入 ResponseWriter 和 数据。
    • 这会触发模板引擎组合解析好的模板和数据,来产生最终的 HTML,并将它传递给 ResponseWriter

代码示例:

其中模板文件 hello.html 的写法:

解析模板

ParseFiles()

  • 解析模板文件,并创建一个解析好的模板 struct,后续可以被执行
  • ParseFiles 函数是 Template struct 上 ParseFiles 方法的简便调用
  • 调用 ParseFiles 后,会创建一个新的模板 ( template.New() ) ,模板的名字是文件名
  • ParseFiles 的参数数量可变,但只返回一个模板
    • 当解析多个文件时,第一个文件作为返回的模板(名、内容),其余的作为 map,供后续执行使用
  • template.ParseFiles() 处理过程:
    1. 先把模板文件的内容读成字符串
    2. 然后使用模板文件名(不包含路径)创建一个新的模板( Template struct )
    3. 再调用该模板的 Parse() 方法来解析模板文件中的字符串

使用示例:

ParseGlob()

使用模式匹配来解析特定的文件
例:template.ParseGlob("*.html")

其他方法

Parse()
可以解析字符串模板,其它方式最终都会调用 Parse

Lookup()
通过模板名来寻找模板,如果没找到就返回 nil

Must()
可以包裹一个函数,返回到一个模板的指针 和 一个错误。
如果错误不为 nil,那么就 panic

执行模板

使用示例:

综合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"html/template"
"log"
"net/http"
)

func main() {
result := loadTemplates() // 模板集

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fileName := r.URL.Path[1:] + ".html" // 从请求的 URL.Path 中截取出 '/' 后面的文件名
t := result.Lookup(fileName) // 通过文件名找到同名的模板,在模板集的树形结构中寻找
if t != nil {
err := t.Execute(w, nil)
if err != nil {
log.Fatalln(err.Error())
}
} else {
w.WriteHeader(http.StatusNotFound)
}
})

http.Handle("/css/", http.FileServer(http.Dir("www/wxy"))) // html 中引用了外部 css ,但没有路径

http.ListenAndServe("localhost:8080", nil)
}

// 在程序启动时,一次性加载所有模板
func loadTemplates() *template.Template {
result := template.New("templates") // 新建模板,名字随意,作为所有模板的容器,是一个模板集
template.Must(result.ParseGlob("templates/*.html")) // 解析 templates 目录下的所有 html 模板
// 如果没有模板,Must() 会panic ,程序终止
return result
}