开放的编程资料库

当前位置:我爱分享网 > Go教程 > 正文

在Golang中创建模板

Go模板教程展示了如何使用标准库在Golang中创建模板。

$ go version
go version go1.18.1 linux/amd64

我们使用Go版本1.18。

模板引擎或模板处理器是一个库,旨在将模板与数据模型结合起来以生成文档。模板引擎通常用于生成大量电子邮件、源代码预处理或生成动态HTML页面。

我们创建了一个模板引擎,我们在其中定义了静态部分和动态部分。动态部分稍后会被数据替换。呈现功能稍后将模板与数据组合。模板引擎用于将模板与数据模型结合起来以生成文档。

Go包含两个模板包:text/templatehtml/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页面,其中包含/usersURL路径的用户表。

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教程。

未经允许不得转载:我爱分享网 » 在Golang中创建模板

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏