Go模板教程展示了如何使用标准库在Golang中创建模板。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
模板引擎或模板处理器是一个库,旨在将模板与数据模型结合起来以生成文档。模板引擎通常用于生成大量电子邮件、源代码预处理或生成动态HTML页面。
我们创建了一个模板引擎,我们在其中定义了静态部分和动态部分。动态部分稍后会被数据替换。呈现功能稍后将模板与数据组合。模板引擎用于将模板与数据模型结合起来以生成文档。
Go包含两个模板包:text/template
和html/template
。两者共享相同的界面。html/template
自动保护HTML输出免受某些攻击。
在模板API中,Parse
函数解析程序中存在的模板字符串,ParseFiles
加载和解析模板文件,Execute
呈现一个使用特定数据字段输出的模板。New
函数使用给定的名称分配一个新的、未定义的模板。
与许多其他模板引擎类似,数据评估和控制结构由{{
和}}
分隔。
Go模板解析
Parse
函数解析Go程序中的模板字符串。
package main import ( "log" "os" "text/template" ) type User struct { Name string Occupation string } func main() { user := User{"John Doe", "gardener"} tmp := template.New("simple") tmp, err := tmp.Parse("{{.Name}} is a {{.Occupation}}") if err != nil { log.Fatal(err) } err2 := tmp.Execute(os.Stdout, user) if err2 != nil { log.Fatal(err2) } }
该示例创建了一条简单的文本消息。
type User struct { Name string Occupation string }
这是模板中使用的数据类型;字段必须导出,即大写。
tmp := template.New("simple")
创建了一个新模板。
tmp, err := tmp.Parse("{{.Name}} is a {{.Occupation}}")
我们使用Parse
来解析模板字符串。使用点运算符,我们访问传递给模板引擎的字段。
$ go run main.go John Doe is a gardener
Go模板必须
Must
函数是一个辅助函数,负责错误检查。
package main import ( "log" "os" "text/template" ) type User struct { Name string Occupation string } func main() { user := User{"John Doe", "gardener"} tmp := template.Must(template.New("simple").Parse("{{.Name}} is a {{.Occupation}}")) f, err := os.Create("output.txt") if err != nil { log.Fatal(err) } defer f.Close() err2 := tmp.Execute(f, user) if err2 != nil { log.Fatal(err2) } }
在示例中,我们使用模板将消息写入文件。我们还使用了Must
函数。
$ go run main.go $ cat output.txt John Doe is a gardener
Go模板ParseFiles
ParseFiles
函数创建一个新模板并从给定的文件名中解析模板定义。
{{.Name}} is a {{.Occupation}}
这是模板文件。
package main import ( "log" "os" "text/template" ) type User struct { Name string Occupation string } func main() { user := User{"John Doe", "gardener"} tmp, err := template.ParseFiles("message.txt") if err != nil { log.Fatal(err) } err2 := tmp.Execute(os.Stdout, user) if err2 != nil { log.Fatal(err2) } }
在示例中,我们从模板文件创建了一条简单的消息。
Go模板范围
range
指令遍历模板中的数组、切片、映射或通道的项目。
{{range .Words -}} {{ .}} {{end}}
在模板中,我们使用range
指令遍历Words
数据结构的元素。-
字符去除空白字符。
package main import ( "log" "os" "text/template" ) type Data struct { Words []string } func main() { data := Data{Words: []string{"sky", "blue", "forest", "tavern", "cup", "cloud"}} tmp, err := template.ParseFiles("words.txt") if err != nil { log.Fatal(err) } err2 := tmp.Execute(os.Stdout, data) if err2 != nil { log.Fatal(err2) } }
在程序中,我们将一段单词传递给模板引擎。我们得到一个单词列表作为输出。
$ go run main.go sky blue forest tavern cup cloud
Go模板条件
可以使用if/elseif/else
指令创建条件。
{{- range .Todos -}} {{if .Done}} {{- .Title -}} {{end}} {{end}}
在模板文件中,我们使用if
指令只输出已完成的任务。
package main import ( "log" "os" "text/template" ) type Todo struct { Title string Done bool } type Data struct { Todos []Todo } func main() { data := Data{Todos: []Todo{ {Title: "Task 1", Done: false}, {Title: "Task 2", Done: true}, {Title: "Task 3", Done: true}, {Title: "Task 4", Done: false}, {Title: "Task 5", Done: true}, }} tmp := template.Must(template.ParseFiles("data.txt")) err2 := tmp.Execute(os.Stdout, data) if err2 != nil { log.Fatal(err2) } }
我们从一片待办事项中生成输出。只有完成的任务才会包含在输出中。
Go模板服务器示例
以下示例在服务器应用程序中使用模板。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Users</title> </head> <body> <table> <thead> <tr> <th>Name</th> <th>Occupation</th> </tr> </thead> <tbody> {{ range .Users}} <tr> <td>{{.Name}}</td> <td>{{.Occupation}}</td> </tr> {{ end }} </tbody> </table> </body> </html>
输出是一个HTML文件。数据被插入到HTML表格中。
package main import ( "html/template" "log" "net/http" ) type User struct { Name string Occupation string } type Data struct { Users []User } func main() { tmp := template.Must(template.ParseFiles("layout.html")) http.HandleFunc("/users", func(w http.ResponseWriter, _ *http.Request) { data := Data{ Users: []User{ {Name: "John Doe", Occupation: "gardener"}, {Name: "Roger Roe", Occupation: "driver"}, {Name: "Peter Smith", Occupation: "teacher"}, }, } tmp.Execute(w, data) }) log.Println("Listening...") http.ListenAndServe(":8080", nil) }
Web服务器返回一个HTML页面,其中包含/users
URL路径的用户表。
Go电子邮件模板
在下面的示例中,我们使用电子邮件模板为多个用户生成电子邮件。我们使用Mailtrap电子邮件测试服务。
$ mkdir template $ cd template $ go mod init com/zetcode/TemplateEmail $ go get github.com/shopspring/decimal
我们启动项目并添加外部github.com/shopspring/decimal
包。
package main import ( "bytes" "fmt" "log" "net/smtp" "text/template" "github.com/shopspring/decimal" ) type Mail struct { Sender string To string Subject string Body bytes.Buffer } type User struct { Name string Email string Debt decimal.Decimal } func main() { sender := "john.doe@example.com" var users = []User{ {"Roger Roe", "roger.roe@example.com", decimal.NewFromFloat(890.50)}, {"Peter Smith", "peter.smith@example.com", decimal.NewFromFloat(350)}, {"Lucia Green", "lucia.green@example.com", decimal.NewFromFloat(120.80)}, } my_user := "username" my_password := "password" addr := "smtp.mailtrap.io:2525" host := "smtp.mailtrap.io" subject := "Amount due" var template_data = ` Dear {{ .Name }}, your debt amount is ${{ .Debt }}.` for _, user := range users { t := template.Must(template.New("template_data").Parse(template_data)) var body bytes.Buffer err := t.Execute(&body, user) if err != nil { log.Fatal(err) } request := Mail{ Sender: sender, To: user.Email, Subject: subject, Body: body, } msg := BuildMessage(request) auth := smtp.PlainAuth("", my_user, my_password, host) err2 := smtp.SendMail(addr, auth, sender, []string{user.Email}, []byte(msg)) if err2 != nil { log.Fatal(err) } } fmt.Println("Emails sent successfully") } func BuildMessage(mail Mail) string { msg := "" msg += fmt.Sprintf("From: %s\r\n", mail.Sender) msg += fmt.Sprintf("To: %s\r\n", mail.To) msg += fmt.Sprintf("Subject: %s\r\n", mail.Subject) msg += fmt.Sprintf("\r\n%s\r\n", mail.Body.String()) return msg }
在示例中,我们向多个用户发送电子邮件以提醒他们他们的债务。
var users = []User{ {"Roger Roe", "roger.roe@example.com", decimal.NewFromFloat(890.50)}, {"Peter Smith", "peter.smith@example.com", decimal.NewFromFloat(350)}, {"Lucia Green", "lucia.green@example.com", decimal.NewFromFloat(120.80)}, }
这些是借款人。
var template_data = ` Dear {{ .Name }}, your debt amount is ${{ .Debt }}.`
这是模板;它包含一个通用消息,其中.Name
和.Debt
占位符被替换为实际值。
for _, user := range users { t := template.Must(template.New("template_data").Parse(template_data)) var body bytes.Buffer err := t.Execute(&body, user) if err != nil { log.Fatal(err) } request := Mail{ Sender: sender, To: user.Email, Subject: subject, Body: body, } msg := BuildMessage(request) auth := smtp.PlainAuth("", my_user, my_password, host) err2 := smtp.SendMail(addr, auth, sender, []string{user.Email}, []byte(msg)) if err2 != nil { log.Fatal(err) } }
我们遍历借款人切片并为他们每个人生成一封电子邮件。Execute
函数将已解析的模板应用于指定的数据对象。消息生成后,用SendMail
发送。
在本教程中,我们使用内置模板包创建了动态文档。
列出所有Go教程。