Matuto的博客

Matuto的博客

马图图

岁月变迁何必不悔,尘世喧嚣怎能无愧。

25 文章数
1 评论数
Go

Golang中tmpl模板的使用

马图图
2023-09-13 / 0 评论 / 691 阅读 / 0 点赞

Golang中tmpl模板的使用

本文介绍了在golang中使用tmpl模板,记录了一些使用方法及常用的模板语法,最后的最后就是遇到的一个坑。

模板与渲染

在前后端不分离的开发场景中,我们需要将一些数据动态的渲染到文档中,实现动态效果。我们就可以通过模板渲染的方式进行。

这里的模板就是指事先定义好的一些文档文件,渲染就是通过类似文本替换的操作,使用相应的数据去替换文档中事先定义好的一些标记。

Golang的模板

golang中内置了两种模板引擎,text/template 和 html/template (这里再实际应用中还碰到了一个坑,后边再说)

使用模板引擎

1.定义模板文件

这里需要按照相关语法去编写。

2.解析模板文件

func (t *Template) Parse(text string) (*Template, error)
func (t *Template) ParseFiles(filenames ...string) (*Template, error)
func (t *Template) ParseGlob(pattern string) (*Template, error)

3.模板渲染

func (t *Template) Execute(wr io.Writer, data any)

模板语法

{{.FieldName}}

模板语法都包含在{{}}中间,其中的.表示当前对象。

当我们传入一个对象时,使用{{.FieldName(字段名)}}的方式来访问。

import (
    "os"
    "strings"
    "text/template"
)

var tmplStr = `Hello {{.Name}}`

type Student struct {
    Name string
}

func main() {
    tmpl := template.Must(template.New("").Parse(tmplStr))
    stu := Student{
        Name: "张三",
    }
    err := tmpl.Execute(os.Stdout, stu)
    if err != nil {
        return
    }
}

变量

可以在模板中声明变量

$obj := {{.FieldName}}

判断

模板中支持if语句,语法:{{if 判断条件}}{{else}}{{end}}

var tmplStr = `{{if .IsStu}}{{.Name}}是一个学生{{else}}{{.Name}}不是一个学生{{end}}`

type Student struct {
    Name  string
    IsStu bool
}

func main() {
    tmpl := template.Must(template.New("").Parse(tmplStr))
    stu := Student{
        Name:  "张三",
        IsStu: true,
    }
    err := tmpl.Execute(os.Stdout, stu)
    if err != nil {
        return
    }
}

控制台输出:张三是一个学生

循环

模板中可以使用range 语句进行循环处理,语法:{{range .数据字段名}}{{end}}

var tmplStr = `{{range .Grade}}学科:{{.Name}}的成绩是 {{.Score}}{{end}}`

type Student struct {
    Name  string
    IsStu bool
    Grade []Subject
}
type Subject struct {
    Name  string
    Score int
}

func main() {
    tmpl := template.Must(template.New("").Parse(tmplStr))
    stu := Student{
        Name:  "张三",
        IsStu: true,
        Grade: []Subject{
            {Name: "语文", Score: 90},
            {Name: "数学", Score: 80},
            {Name: "英语", Score: 70},
        },
    }
    err := tmpl.Execute(os.Stdout, stu)
    if err != nil {
        return
    }
}

控制台输出:学科:语文的成绩是 90学科:数学的成绩是 80学科:英语的成绩是 70

在循环中直接使用数组中对象的字段就可以了

比较

eq      如果arg1 == arg2则返回真
ne      如果arg1 != arg2则返回真
lt      如果arg1 < arg2则返回真
le      如果arg1 <= arg2则返回真
gt      如果arg1 > arg2则返回真
ge      如果arg1 >= arg2则返回真

eq配合if进行使用

var tmplStr = `{{if eq .Name "张三"}}班长{{else}}普通学生{{end}}`

type Student struct {
    Name  string
    IsStu bool
    Grade []Subject
}
type Subject struct {
    Name  string
    Score int
}

func main() {
    tmpl := template.Must(template.New("").Parse(tmplStr))
    stu := Student{
        Name:  "张三",
        IsStu: true,
        Grade: []Subject{
            {Name: "语文", Score: 90},
            {Name: "数学", Score: 80},
            {Name: "英语", Score: 70},
        },
    }
    err := tmpl.Execute(os.Stdout, stu)
    if err != nil {
        return
    }
}

控制台输出:班长

自定义函数

在实际使用中,模板引擎中提供的函数不能满足需求,这个时候就可以自定义一些函数注册到模板引擎中进行使用,示例如下:

var tmplStr = `{{if Contains .Hobby "学习"}}{{.Name}}喜欢学习{{else}}他不喜欢{{end}}`

type Student struct {
    Name  string
    IsStu bool
    Grade []Subject
    Hobby string
}
type Subject struct {
    Name  string
    Score int
}

func main() {
    parse, err := template.New("").Funcs(template.FuncMap{
        "Contains": Contains,
    }).Parse(tmplStr)
    if err != nil {
        return
    }
    stu := Student{
        Name:  "张三",
        IsStu: true,
        Hobby: "游泳,学习,看书,游戏",
    }
    err = parse.Execute(os.Stdout, stu)
    if err != nil {
        return
    }
}

// Contains 判断字符串是否包含
func Contains(s, t string) bool {
    return strings.Contains(s, t)
}

控制台输出:张三喜欢学习

这里定义了一个 Contains 函数 用于判断字符串中是否包含子串,使用 Funcs 函数进行自定义函数的注册。

注:自定义函数的首字母一定要大写,不然模板引擎中访问不到该函数。

text/template与html/tempalte的区别

text/template 是将内容都已text文本格式返回。

html/tempalte针对的是需要返回HTML内容的场景。 在模板渲染过程中会对一些有风险的内容进行转义,以此来防范跨站脚本攻击。

当传入一段JS代码并使用html/template去渲染该文件,会在页面上显示出转义后的JS内容。 <script>alert('这是一个弹框')</script>这就是html/template为我们做的事。 但当有人恶意传入一个死循环的JS内容或一些占用资源比较大的内容,将会造成危险。

坑记录

在编写代码生成器时,使用了模板语法,一开始并未注意使用的是html/tempalte。

在模板中进行变量输出时,老是会在变量两边加上 双引号“” 网上的解释是 ”如果 .ObjectName 是一个字符串类型的变量,生成的代码会默认添加双引号“

从网上找到两种解决方式,两种方法都是对字符串进行处理。

1:使用 printf 函数:在模板中,您可以使用 printf 函数来生成不带双引号的代码。

name: '{{printf "%s" .ObjectName}}Add',
// 把值传回了{{printf "%s" .ObjectName}}Add
props: {
    visible: Boolean, // 更新了<{{printf "%s" .ObjectName}}Add v-model:visible
    name: String
},

2:使用 strings.Trim 函数来删除生成的代码中的双引号

strings.Trim(s, "\"")

发现都不好用,还是不起作用。

解决方法

不用猜了,使用 text/template 包就好了,具体原因还不清楚,有空了还需要研究一下。

项目示例

依据template做了一个代码生成器,目前能根据数据库的pdm文件或连接MySQL数据库生成基本的增删改查功能,包含golang+vue+js的代码,有兴趣的可以看一下。 项目地址:https://github.com/majingzhen/codeGenerator-Go

上一篇 下一篇
评论
来首音乐
最新回复
光阴似箭
今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月
文章目录
每日一句