goweb项目结构以及如何实现前后端交互
项目结构
HTML模板
使用ParseFiles可以解析多个模板文件
func ParseFiles(filenames ...string)(*Teplate,error){return parseFiles(nil,filenames...)
}
把模板信息响应写入到输入流中
func (t *Template) Exwcute(wr io.Writer,data interface{})error{if err:=t.escape();err!=nil{return err}return t.text.Execute(wr,data)
}
index.js
function myclick(){alert("您点击了按钮")
}
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
html
<button onclick="myclick()">按钮</button>
</body>
</html>
main.go
package mainimport ("html/template""net/http"
)func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html")t.Execute(w, nil)
}func main() {server := http.Server{Addr: ":8090"}//当发现url以/static开头把请求转发给指定的路径http.Handle("/demo/static/", http.StripPrefix("/demo/static/", http.FileServer(http.Dir("demo/static"))))http.HandleFunc("/", welcome)server.ListenAndServe()
}
向模板传递数据
可以在HTML中使用{f}获取template.Execute()第二个参数传递的值
最常用的 {{.}} 中的""是指针,指向当前变量,称为"dot”
在{{}}可以有的Argument,官方给定如下
向HTML传递字符串数据,在HTML中使用((.})获取传递数据即可,所有基本类型都是使用此方式进行传递
传递普通值类型
main.go
package mainimport ("html/template""net/http"
)func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html")t.Execute(w, "smallming")}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
{{.}}
</body>
</html>
运行后在浏览器显示smallming
传递结构体类型数据
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
获取到的数据:
姓名 {{.Name}}<br/>
年龄 {{.Age}}
</body>
</html>
main.go
package mainimport ("html/template""net/http"
)type User struct {Name stringAge int
}func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html")t.Execute(w, User{"zhang", 18})}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
传递Map数据
main.go
package mainimport ("html/template""net/http"
)type User struct {Name stringAge int
}func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html")m := make(map[string]interface{})m["user"] = User{"zhang", 18}m["money"] = 88888888888t.Execute(w, m)}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
获取到的数据:
姓名 {{.user.Name}}<br/>
年龄 {{.user.Age}}<br/>
财富 {{.money}}
</body>
</html>
在模板中调用函数
在模版中调用函数时,如果是无参函数直接调用函数名即可,没有函数的括号
例如在go源码中 时间变量,year()在模版中 {{时间.Year}}
在模版中调用有参函数时参数和函数名称之间有空格,参数和参数之间也是空格
给定go文件代码
调用给定的方法
mian.go
package mainimport ("html/template""net/http""time"
)type User struct {Name stringAge int
}func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html")time := time.Date(2004, 3, 3, 5, 7, 3, 2, time.Local)t.Execute(w, time)}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
获取到的数据:
完整时间 {{.}}<br/>
年{{.Year}}<br/>
月 {{.Month}}<br/>
转换后的格式
{{.Format "2006-01-02 15:04:03"}}
</body>
</html>
调用自定义方法
如果希望调用自定义函数,需要借助html/template包下的FuncMap进行映射
FuncMap本质就是map的别名 type FuncMap map[string]interface{}
函数被添加映射后,只能通过函数在FuncMap中的key调用函数
main.go
package mainimport ("html/template""net/http""time"
)type User struct {Name stringAge int
}func MyTransfer(t time.Time) string {return t.Format("2006-03-05 15:02:04")
}func welcome(w http.ResponseWriter, r *http.Request) {//把自定义函数绑定在funcMap上fm := template.FuncMap{"mt": MyTransfer}t := template.New("index.html").Funcs(fm)t, _ = t.ParseFiles("demo/view/index.html")time1 := time.Date(2018, 1, 2, 3, 4, 5, 0, time.Local)t.Execute(w, time1)}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
获取到的数据:
完整时间 {{.}}<br/>
年{{.Year}}<br/>
月 {{.Month}}<br/>
转换后的格式<br/>
{{.Format "2006-01-02 15:04:03"}}<br/>
调用自定义函数<br/>
{{mt .}}
</body>
</html>
action
Go语言官方文档给出action(动作)的列表。"Arguments"和"pipelines"代表数据的执行结果
-
{{/*a comment */}}
注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止,就像这里表示的一样。
-
{{pipeline}}
pipeline的值的默认文本表示会被拷贝到输出里 -
{fif pipeline}} T1 {{end}}
如果pipeline的值为empty,不产生输出,否则输出T1执行结果。不改变dot的值
Empty值包括false、0、任意nil指针或者ni1接口,任意长度为8的数组、切片、字典。
-
{{if pipeline}} T1 {{else}} To {{end}}
-
如果pipeline的值为empty,输出T执行结果,否则输出T1执行结果。不改变dot的值
-
{{if pipeline}} T1 {{else if pipeline}} re {{end}}
用于简化if-else链条,else action可以直接包含另一个if;等价于:
{{if pipeline}} T1 {{else}}{{if pipeline}} To {{end}}{{end}}
-
{{range pipeline}} T1{{end}}
pipeline的值必须是数组、切片、字典或者通道
如果pipeline的值其长度为0,不会有任何输出;
否则dot依次设为数组、切片、字典或者通道的每一个成员元素并执行T1;
如果pipeline的值为字典,且键可排序的基本类型,元素也会按键的顺序排序。
-
{{range pipeline}} T1 {felse}} To {fend}}
pipeline的值必须是数组、切片、字典或者通道,
如果pipeline的值其长度为8,不改变dot的值并执行T0;否则会修改dot并执行T1。
-
{template “name”}}
执行名为name的模板,提供给模板的参数为ni1,如模板不存在输出为""
-
{{template “name” pipeline}}
执行名为name的模板,提供给模板的参数为pipeline的值。
-
{{with pipeline}} T1{fend}}
如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot
-
{{with pipeline}} Tl {{else}} To {{end}}
如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。
action主要完成流程控制、循环、模版等操作,通过使用action可以在模版中完成简单逻辑处理(复杂逻辑处理
应该在go中实现,传递给模版的数据应该是已经加工完的数据)
if使用
if写在模版中和写在go文件中功能是相同的,区别是语法
布尔函数会将任何类型的零值视为假,其余视为真。
if后面的表达式中如果包含逻辑控制符在模版中实际上是全局函数
main.go
package mainimport ("html/template""net/http"
)func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html")t.Execute(w, "")}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
取出数据{{.}}<br/>
{{if .}}
执行了if
这相当于if的{}内容
{{else}}
执行了else
{{end}}
html
</body>
</html>
if else if else的用法
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
{{$n:=123}}
{{if gt $n 456}}
执行if
{{else}}
执行else
{{end}}
</body>
</html>
range使用
main.go
package mainimport ("html/template""net/http"
)func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html")arr := []string{"第一个", "第二个"}t.Execute(w, arr)}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
index.go
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript" src="/demo/static/js/index.js"></script>
</head>
<body>
{{range .}}
{{.}}<br/>
{{end}}
</body>
</html>
结果
如果是map的话直接取出map的value
模板嵌套
在实际项目中经常出现页面复用的情况,例如:整个网站的头部信息和底部信息复用可以使用动作{{template"模版名称"}}引用模版。引用的模版必须在HTML中定义这个模版
{{define“名称”}}
htm1
{{end}}
执行主模版时也要给主模版一个名称,执行时调用的是ExecuteTemplate()方法
main.go
package mainimport ("html/template""net/http"
)func welcome(w http.ResponseWriter, r *http.Request) {t, _ := template.ParseFiles("demo/view/index.html", "demo/view/head.html", "demo/view/foot.html")t.ExecuteTemplate(w, "layout", nil)
}func main() {server := http.Server{Addr: ":8090"}http.HandleFunc("/", welcome)server.ListenAndServe()
}
index.html
{{define "layout"}}
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Document</title>
</head>
<body>
{{template "head" "传递head过去的内容"}}<br/>
中间内容<br/>
{{template "foot" "传递foot过去的内容"}}<br/>
</body>
</html>
{{end}}
head.html
{{define "head"}}
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Document</title>
</head>
<body>
head {{.}}
</body>
</html>
{{end}}
foot.html
{{define "foot"}}
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Document</title>
</head>
<body>
foot {{.}}
</body>
</html>
{{end}}
运行结果