Format and remove 07.4.md spaces

This commit is contained in:
vCaesar
2017-06-10 12:01:02 +08:00
parent aff9e4a0cd
commit 74268581ba

View File

@@ -14,12 +14,12 @@ Web应用反馈给客户端的信息中的大部分内容是静态的不变
在Go语言中我们使用`template`包来进行模板处理,使用类似`Parse``ParseFile``Execute`等方法从文件或者字符串加载模板然后执行类似上面图片展示的模板的merge操作。请看下面的例子
```Go
func handler(w http.ResponseWriter, r *http.Request) {
t := template.New("some template") //创建一个模板
t, _ = t.ParseFiles("tmpl/welcome.html", nil) //解析模板文件
user := GetUser() //获取当前用户信息
t.Execute(w, user) //执行模板的merger操作
}
func handler(w http.ResponseWriter, r *http.Request) {
t := template.New("some template") //创建一个模板
t, _ = t.ParseFiles("tmpl/welcome.html", nil) //解析模板文件
user := GetUser() //获取当前用户信息
t.Execute(w, user) //执行模板的merger操作
}
```
通过上面的例子我们可以看到Go语言的模板操作非常的简单方便和其他语言的模板处理类似都是先获取数据然后渲染数据。
@@ -36,33 +36,33 @@ Web应用反馈给客户端的信息中的大部分内容是静态的不变
Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{.}}`表示当前的对象这和Java或者C++中的this类似如果要访问当前对象的字段通过`{{.FieldName}}`,但是需要注意一点:这个字段必须是导出的(字段首字母必须是大写的),否则在渲染的时候就会报错,请看下面的这个例子:
```Go
package main
package main
import (
"html/template"
"os"
)
import (
"html/template"
"os"
)
type Person struct {
UserName string
}
type Person struct {
UserName string
}
func main() {
t := template.New("fieldname example")
t, _ = t.Parse("hello {{.UserName}}!")
p := Person{UserName: "Astaxie"}
t.Execute(os.Stdout, p)
}
func main() {
t := template.New("fieldname example")
t, _ = t.Parse("hello {{.UserName}}!")
p := Person{UserName: "Astaxie"}
t.Execute(os.Stdout, p)
}
```
上面的代码我们可以正确的输出`hello Astaxie`,但是如果我们稍微修改一下代码,在模板中含有了未导出的字段,那么就会报错
```Go
type Person struct {
UserName string
email string //未导出的字段,首字母是小写的
}
type Person struct {
UserName string
email string //未导出的字段,首字母是小写的
}
t, _ = t.Parse("hello {{.UserName}}! {{.email}}")
t, _ = t.Parse("hello {{.UserName}}! {{.email}}")
```
上面的代码就会报错,因为我们调用了一个未导出的字段,但是如果我们调用了一个不存在的字段是不会报错的,而是输出为空。
@@ -77,67 +77,67 @@ Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{
详细的使用请看下面的例子:
```Go
package main
package main
import (
"html/template"
"os"
)
import (
"html/template"
"os"
)
type Friend struct {
Fname string
}
type Friend struct {
Fname string
}
type Person struct {
UserName string
Emails []string
Friends []*Friend
}
type Person struct {
UserName string
Emails []string
Friends []*Friend
}
func main() {
f1 := Friend{Fname: "minux.ma"}
f2 := Friend{Fname: "xushiwei"}
t := template.New("fieldname example")
t, _ = t.Parse(`hello {{.UserName}}!
{{range .Emails}}
an email {{.}}
{{end}}
{{with .Friends}}
{{range .}}
my friend name is {{.Fname}}
{{end}}
{{end}}
`)
p := Person{UserName: "Astaxie",
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"},
Friends: []*Friend{&f1, &f2}}
t.Execute(os.Stdout, p)
}
func main() {
f1 := Friend{Fname: "minux.ma"}
f2 := Friend{Fname: "xushiwei"}
t := template.New("fieldname example")
t, _ = t.Parse(`hello {{.UserName}}!
{{range .Emails}}
an email {{.}}
{{end}}
{{with .Friends}}
{{range .}}
my friend name is {{.Fname}}
{{end}}
{{end}}
`)
p := Person{UserName: "Astaxie",
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"},
Friends: []*Friend{&f1, &f2}}
t.Execute(os.Stdout, p)
}
```
### 条件处理
在Go模板里面如果需要进行条件判断那么我们可以使用和Go语言的`if-else`语法类似的方式来处理如果pipeline为空那么if就认为是false下面的例子展示了如何使用`if-else`语法:
```Go
package main
package main
import (
"os"
"text/template"
)
import (
"os"
"text/template"
)
func main() {
tEmpty := template.New("template test")
tEmpty = template.Must(tEmpty.Parse("空 pipeline if demo: {{if ``}} 不会输出. {{end}}\n"))
tEmpty.Execute(os.Stdout, nil)
func main() {
tEmpty := template.New("template test")
tEmpty = template.Must(tEmpty.Parse("空 pipeline if demo: {{if ``}} 不会输出. {{end}}\n"))
tEmpty.Execute(os.Stdout, nil)
tWithValue := template.New("template test")
tWithValue = template.Must(tWithValue.Parse("不为空的 pipeline if demo: {{if `anything`}} 我有内容,我会输出. {{end}}\n"))
tWithValue.Execute(os.Stdout, nil)
tWithValue := template.New("template test")
tWithValue = template.Must(tWithValue.Parse("不为空的 pipeline if demo: {{if `anything`}} 我有内容,我会输出. {{end}}\n"))
tWithValue.Execute(os.Stdout, nil)
tIfElse := template.New("template test")
tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if部分 {{else}} else部分.{{end}}\n"))
tIfElse.Execute(os.Stdout, nil)
}
tIfElse := template.New("template test")
tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if部分 {{else}} else部分.{{end}}\n"))
tIfElse.Execute(os.Stdout, nil)
}
```
通过上面的演示代码我们知道`if-else`语法相当的简单,在使用过程中很容易集成到我们的模板代码中。
@@ -147,8 +147,8 @@ Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{
Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的语法你是不是经常使用,过滤当前目录下面的文件,显示含有"beego"的数据表达的意思就是前面的输出可以当做后面的输入最后显示我们想要的数据而Go语言模板最强大的一点就是支持pipe数据在Go语言里面任何`{{}}`里面的都是pipelines数据例如我们上面输出的email里面如果还有一些可能引起XSS注入的那么我们如何来进行转化呢
```Go
{{. | html}}
{{. | html}}
```
在email输出的地方我们可以采用如上方式可以把输出全部转化html的实体上面的这种方式和我们平常写Unix的方式是不是一模一样操作起来相当的简便调用其他的函数也是类似的方式。
@@ -156,14 +156,14 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的
有时候,我们在模板使用过程中需要定义一些局部变量,我们可以在一些操作中申明局部变量,例如`with``range``if`过程中申明局部变量,这个变量的作用域是`{{end}}`之前Go语言通过申明的局部变量格式如下所示
```Go
$variable := pipeline
$variable := pipeline
```
详细的例子看下面的:
```Go
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
```
### 模板函数
@@ -172,194 +172,194 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的
每一个模板函数都有一个唯一值的名字然后与一个Go函数关联通过如下的方式来关联
```Go
type FuncMap map[string]interface{}
type FuncMap map[string]interface{}
```
例如如果我们想要的email函数的模板函数名是`emailDeal`它关联的Go函数名称是`EmailDealWith`,那么我们可以通过下面的方式来注册这个函数
```Go
t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith})
t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith})
```
`EmailDealWith`这个函数的参数和返回值定义如下:
```Go
func EmailDealWith(args interface{}) string
func EmailDealWith(args interface{}) string
```
我们来看下面的实现例子:
```Go
package main
package main
import (
"fmt"
"html/template"
"os"
"strings"
)
import (
"fmt"
"html/template"
"os"
"strings"
)
type Friend struct {
Fname string
type Friend struct {
Fname string
}
type Person struct {
UserName string
Emails []string
Friends []*Friend
}
func EmailDealWith(args ...interface{}) string {
ok := false
var s string
if len(args) == 1 {
s, ok = args[0].(string)
}
type Person struct {
UserName string
Emails []string
Friends []*Friend
if !ok {
s = fmt.Sprint(args...)
}
func EmailDealWith(args ...interface{}) string {
ok := false
var s string
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
s = fmt.Sprint(args...)
}
// find the @ symbol
substrs := strings.Split(s, "@")
if len(substrs) != 2 {
return s
}
// replace the @ by " at "
return (substrs[0] + " at " + substrs[1])
// find the @ symbol
substrs := strings.Split(s, "@")
if len(substrs) != 2 {
return s
}
// replace the @ by " at "
return (substrs[0] + " at " + substrs[1])
}
func main() {
f1 := Friend{Fname: "minux.ma"}
f2 := Friend{Fname: "xushiwei"}
t := template.New("fieldname example")
t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith})
t, _ = t.Parse(`hello {{.UserName}}!
{{range .Emails}}
an emails {{.|emailDeal}}
{{end}}
{{with .Friends}}
{{range .}}
my friend name is {{.Fname}}
{{end}}
{{end}}
`)
p := Person{UserName: "Astaxie",
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"},
Friends: []*Friend{&f1, &f2}}
t.Execute(os.Stdout, p)
}
func main() {
f1 := Friend{Fname: "minux.ma"}
f2 := Friend{Fname: "xushiwei"}
t := template.New("fieldname example")
t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith})
t, _ = t.Parse(`hello {{.UserName}}!
{{range .Emails}}
an emails {{.|emailDeal}}
{{end}}
{{with .Friends}}
{{range .}}
my friend name is {{.Fname}}
{{end}}
{{end}}
`)
p := Person{UserName: "Astaxie",
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"},
Friends: []*Friend{&f1, &f2}}
t.Execute(os.Stdout, p)
}
```
上面演示了如何自定义函数,其实,在模板包内部已经有内置的实现函数,下面代码截取自模板包里面
```Go
var builtins = FuncMap{
"and": and,
"call": call,
"html": HTMLEscaper,
"index": index,
"js": JSEscaper,
"len": length,
"not": not,
"or": or,
"print": fmt.Sprint,
"printf": fmt.Sprintf,
"println": fmt.Sprintln,
"urlquery": URLQueryEscaper,
}
var builtins = FuncMap{
"and": and,
"call": call,
"html": HTMLEscaper,
"index": index,
"js": JSEscaper,
"len": length,
"not": not,
"or": or,
"print": fmt.Sprint,
"printf": fmt.Sprintf,
"println": fmt.Sprintln,
"urlquery": URLQueryEscaper,
}
```
## Must操作
模板包里面有一个函数`Must`它的作用是检测模板是否正确例如大括号是否匹配注释是否正确的关闭变量是否正确的书写。接下来我们演示一个例子用Must来判断模板是否正确
```Go
package main
package main
import (
"fmt"
"text/template"
)
import (
"fmt"
"text/template"
)
func main() {
tOk := template.New("first")
template.Must(tOk.Parse(" some static text /* and a comment */"))
fmt.Println("The first one parsed OK.")
func main() {
tOk := template.New("first")
template.Must(tOk.Parse(" some static text /* and a comment */"))
fmt.Println("The first one parsed OK.")
template.Must(template.New("second").Parse("some static text {{ .Name }}"))
fmt.Println("The second one parsed OK.")
template.Must(template.New("second").Parse("some static text {{ .Name }}"))
fmt.Println("The second one parsed OK.")
fmt.Println("The next one ought to fail.")
tErr := template.New("check parse error with Must")
template.Must(tErr.Parse(" some static text {{ .Name }"))
}
fmt.Println("The next one ought to fail.")
tErr := template.New("check parse error with Must")
template.Must(tErr.Parse(" some static text {{ .Name }"))
}
```
将输出如下内容
```
The first one parsed OK.
The second one parsed OK.
The next one ought to fail.
panic: template: check parse error with Must:1: unexpected "}" in command
The first one parsed OK.
The second one parsed OK.
The next one ought to fail.
panic: template: check parse error with Must:1: unexpected "}" in command
```
## 嵌套模板
我们平常开发Web应用的时候经常会遇到一些模板有些部分是固定不变的然后可以抽取出来作为一个独立的部分例如一个博客的头部和尾部是不变的而唯一改变的是中间的内容部分。所以我们可以定义成`header``content``footer`三个部分。Go语言中通过如下的语法来申明
```Go
{{define "子模板名称"}}内容{{end}}
{{define "子模板名称"}}内容{{end}}
```
通过如下方式来调用:
```Go
{{template "子模板名称"}}
{{template "子模板名称"}}
```
接下来我们演示如何使用嵌套模板,我们定义三个文件,`header.tmpl``content.tmpl``footer.tmpl`文件,里面的内容如下
```html
//header.tmpl
{{define "header"}}
<html>
<head>
<title>演示信息</title>
</head>
<body>
{{end}}
//header.tmpl
{{define "header"}}
<html>
<head>
<title>演示信息</title>
</head>
<body>
{{end}}
//content.tmpl
{{define "content"}}
{{template "header"}}
<h1>演示嵌套</h1>
<ul>
<li>嵌套使用define定义子模板</li>
<li>调用使用template</li>
</ul>
{{template "footer"}}
{{end}}
//content.tmpl
{{define "content"}}
{{template "header"}}
<h1>演示嵌套</h1>
<ul>
<li>嵌套使用define定义子模板</li>
<li>调用使用template</li>
</ul>
{{template "footer"}}
{{end}}
//footer.tmpl
{{define "footer"}}
</body>
</html>
{{end}}
//footer.tmpl
{{define "footer"}}
</body>
</html>
{{end}}
```
演示代码如下:
```Go
package main
package main
import (
"fmt"
"os"
"text/template"
)
import (
"fmt"
"os"
"text/template"
)
func main() {
s1, _ := template.ParseFiles("header.tmpl", "content.tmpl", "footer.tmpl")
s1.ExecuteTemplate(os.Stdout, "header", nil)
fmt.Println()
s1.ExecuteTemplate(os.Stdout, "content", nil)
fmt.Println()
s1.ExecuteTemplate(os.Stdout, "footer", nil)
fmt.Println()
s1.Execute(os.Stdout, nil)
}
func main() {
s1, _ := template.ParseFiles("header.tmpl", "content.tmpl", "footer.tmpl")
s1.ExecuteTemplate(os.Stdout, "header", nil)
fmt.Println()
s1.ExecuteTemplate(os.Stdout, "content", nil)
fmt.Println()
s1.ExecuteTemplate(os.Stdout, "footer", nil)
fmt.Println()
s1.Execute(os.Stdout, nil)
}
```
通过上面的例子我们可以看到通过`template.ParseFiles`把所有的嵌套模板全部解析到模板里面,其实每一个定义的{{define}}都是一个独立的模板他们相互独立是并行存在的关系内部其实存储的是类似map的一种关系(key是模板的名称value是模板的内容),然后我们通过`ExecuteTemplate`来执行相应的子模板内容我们可以看到header、footer都是相对独立的都能输出内容content 中因为嵌套了header和footer的内容就会同时输出三个的内容。但是当我们执行`s1.Execute`,没有任何的输出,因为在默认的情况下没有默认的子模板,所以不会输出任何的东西。