// ParseFiles creates a new Template and parses the template definitions from
// the named files. The returned template's name will have the base name and
// parsed contents of the first file. There must be at least one file.
// If an error occurs, parsing stops and the returned *Template is nil.
//
// When parsing multiple files with the same name in different directories,
// the last one mentioned will be the one that results.
// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
// named "foo", while "a/foo" is unavailable.
func ParseFiles(filenames ...string) (*Template, error) {
return parseFiles(nil, readFileOS, filenames...)
}
// Execute applies a parsed template to the specified data object,
// writing the output to wr.
// If an error occurs executing the template or writing its output,
// execution stops, but partial results may already have been written to
// the output writer.
// A template may be executed safely in parallel, although if parallel
// executions share a Writer the output may be interleaved.
func (t *Template) Execute(wr io.Writer, data interface{}) error {
if err := t.escape(); err != nil {
return err
}
return t.text.Execute(wr, data)
}
package main
import (
"net/http"
"text/template"
)
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("HTML-Template/view/index.gtpl")
files.Execute(res, nil)
}
func main() {
server := http.Server{Addr: "localhost:8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
Hello,HTML.Long time no see.
body>
html>
package main
import (
"net/http"
"text/template"
)
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("importStatic/view/index.gtpl")
files.Execute(res, nil)
}
func main() {
server := http.Server{Addr: "localhost:8090"}
// 当发现url以/static开头时,把请求转发给指定的路径
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("importStatic/static"))))
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script type="text/javascript" src="/static/js/index.js">script>
head>
<body>
Hello,HTML.Long time no see.<br/>
<button onclick="myClick()">按钮button>
body>
html>
function myClick() {
alert("您点击了按钮")
}
// - go语法的布尔值、字符串、字符、整数、浮点数、虚数、复数,视为无类型字面常数,字符串不能跨行
// - 关键字nil,代表一个go的无类型的nil值
// - 字符'.'(句点,用时加单引号),代表dot的值
// - 变量名,以美元符号起始加上(可为空的)字母和数字构成的字符串,如:piOver2和$;
// 执行结果为变量的值,变量请见下面的介绍
// - 结构体数据的字段名,以句点起始,如:.Field;
// 执行结果为字段的值,支持链式调用:.Field1.Field2;
// 字段也可以在变量上使用(包括链式调用):x.Field1.Field2;
// - 字典类型数据的键名:以句点起始,如:.key;
// 执行结果是该键在字典中对应的成员元素的值;
// 键也可以和字段配合做链式调用,深度不限:.Field1.Key1.Field2.Key2;
// 虽然键也必须是字母和数字构成的标识字符串,但不需要以大写字母起始;
// 键也可以用于变量(包括链式调用):x.key1.key2;
// - 数据的无参数方法名,以句点为起始,如:.Method;
// 执行结果为dot调用该方法的返回值,如:dot.Method();
// 该方法必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
// 如果有2个返回值返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;
// 方法可和字段、键配合做链式调用,深度不限:.Field1.Key1.Method1.Field2.Key2.Method2;
// 方法也可以在变量上使用(包括链式调用):$x.Method1.Field;
// - 无参数的函数名,如:fun;
// 执行结果是调用该函数的返回值fun();对返回值的要求和方法一样;函数和函数名细节参见后面。
// - 上面某一条的实例加上括弧(用于分组)
//执行结果可以访问其字段或者键对应的值:
print (.F1 arg1) (.F2 arg2)
(.StructValuedMethod "arg").Field
package main
import (
"net/http"
"text/template"
)
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("dataToTemplate/view/index.gtpl")
files.Execute(res, "stronger")
}
func main() {
server := http.Server{Addr: ":8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<pre>
尊敬的{{.}}先生/女士:
巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉巴拉
再次恭喜您:{{.}}
pre>
body>
html>
package main
import (
"net/http"
"text/template"
)
type User struct {
Name string
Age int
}
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("structToTemplate/view/index.gtpl")
files.Execute(res, User{"张三", 18})
}
func main() {
server := http.Server{Addr: ":8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
获取到的信息:
姓名:{{.Name}}<br/>
年龄:{{.Age}}
body>
html>
package main
import (
"net/http"
"text/template"
)
type User struct {
Name string
Age int
}
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("mapToTemplate/view/index.gtpl")
m := make(map[string]interface{})
m["user"] = User{"张三", 18}
m["money"] = 9999999
files.Execute(res, m)
}
func main() {
server := http.Server{Addr: ":8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
获取到的信息:
姓名:{{.user.Name}}<br/>
年龄:{{.user.Age}}<br/>
薪资:{{.money}}
body>
html>
package main
import (
"net/http"
"text/template"
"time"
)
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("functionInTemplate/view/index.gtpl")
date := time.Date(2025, 3, 13, 3, 4, 5, 0, time.Local)
files.Execute(res, date)
}
func main() {
server := http.Server{Addr: ":8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
完整时间:{{.}}<br/>
年:{{.Year}}<br/>
月:{{.Month}}<br/>
转换后的格式为:{{.Format "2006-01-02 03-04-05"}}
body>
html>
package main
import (
"net/http"
"text/template"
"time"
)
func custom(t time.Time) string {
return t.Format("2006-01-02 03:04:05")
}
func welcome(res http.ResponseWriter, req *http.Request) {
funcMap := template.FuncMap{"cu": custom}
funcs := template.New("index.gtpl").Funcs(funcMap)
files, _ := funcs.ParseFiles("customInTemplate/view/index.gtpl")
date := time.Date(2025, 3, 13, 3, 4, 5, 0, time.Local)
files.Execute(res, date)
}
func main() {
server := http.Server{Addr: ":8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
完整时间:{{.}}<br/>
年:{{.Year}}<br/>
月:{{.Month}}<br/>
转换后的格式为:{{.Format "2006-01-02 03-04-05"}}<br/>
调用自定义函数:{{cu .}}
body>
html>
{{/* a comment */}}
注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止,就像这里表示的一样。
{{pipeline}}
pipeline的值的默认文本表示会被拷贝到输出里。
{{if pipeline}} T1 {{end}}
如果pipeline的值为empty,不产生输出,否则输出T1执行结果。不改变dot的值。
Empty值包括false、0、任意nil指针或者nil接口,任意长度为0的数组、切片、字典。
{{if pipeline}} T1 {{else}} T0 {{end}}
如果pipeline的值为empty,输出T0执行结果,否则输出T1执行结果。不改变dot的值。
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
用于简化if-else链条,else action可以直接包含另一个if;等价于:
{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
{{range pipeline}} T1 {{end}}
pipeline的值必须是数组、切片、字典或者通道。
如果pipeline的值其长度为0,不会有任何输出;
否则dot依次设为数组、切片、字典或者通道的每一个成员元素并执行T1;
如果pipeline的值为字典,且键可排序的基本类型,元素也会按键的顺序排序。
{{range pipeline}} T1 {{else}} T0 {{end}}
pipeline的值必须是数组、切片、字典或者通道。
如果pipeline的值其长度为0,不改变dot的值并执行T0;否则会修改dot并执行T1。
{{template "name"}}
执行名为name的模板,提供给模板的参数为nil,如模板不存在输出为""
{{template "name" pipeline}}
执行名为name的模板,提供给模板的参数为pipeline的值。
{{with pipeline}} T1 {{end}}
如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。
{{with pipeline}} T1 {{else}} T0 {{end}}
如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。
and
函数返回它的第一个empty参数或者最后一个参数;
就是说"and x y"等价于"if x then y else x";所有参数都会执行;
or
返回第一个非empty参数或者最后一个参数;
亦即"or x y"等价于"if x then x else y";所有参数都会执行;
not
返回它的单个参数的布尔值的否定
len
返回它的参数的整数类型长度
index
执行结果为第一个参数以剩下的参数为索引/键指向的值;
如"index x 1 2 3"返回x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
print
即fmt.Sprint
printf
即fmt.Sprintf
println
即fmt.Sprintln
html
返回其参数文本表示的HTML逸码等价表示。
urlquery
返回其参数文本表示的可嵌入URL查询的逸码等价表示。
js
返回其参数文本表示的JavaScript逸码等价表示。
call
执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数;
如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2);
其中Y是函数类型的字段或者字典的值,或者其他类似情况;
call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同);
该函数类型值必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;
eq 如果arg1 == arg2则返回真
ne 如果arg1 != arg2则返回真
lt 如果arg1 < arg2则返回真
le 如果arg1 <= arg2则返回真
gt 如果arg1 > arg2则返回真
ge 如果arg1 >= arg2则返回真
package main
import (
"net/http"
"text/template"
)
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("action_if/view/index.gtpl")
files.Execute(res, "123")
}
func main() {
server := http.Server{Addr: ":8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
{{$n:=123}}
{{if lt $n 456}}
执行if语句
{{else}}
执行else语句
{{end}}
body>
html>
package main
import (
"net/http"
"text/template"
)
func welcome(res http.ResponseWriter, req *http.Request) {
files, _ := template.ParseFiles("action_range/view/index.gtpl")
//strings := []string{"a", "b", "c", "d"}
m := map[string]string{"key1": "value1", "key2": "value2", "key3": "value3", "key4": "value4"}
files.Execute(res, m)
}
func main() {
server := http.Server{Addr: ":8090"}
http.HandleFunc("/", welcome)
server.ListenAndServe()
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
{{range .}}
{{.}}<br/>
{{end}}
body>
html>
{{define "名称"}}
html
{{end}}
// FormFile returns the first file for the provided form key.
// FormFile calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary.
func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
if r.MultipartForm == multipartByReader {
return nil, nil, errors.New("http: multipart handled by MultipartReader")
}
if r.MultipartForm == nil {
err := r.ParseMultipartForm(defaultMaxMemory)
if err != nil {
return nil, nil, err
}
}
if r.MultipartForm != nil && r.MultipartForm.File != nil {
if fhs := r.MultipartForm.File[key]; len(fhs) > 0 {
f, err := fhs[0].Open()
return f, fhs[0], err
}
}
return nil, nil, ErrMissingFile
}
// File is an interface to access the file part of a multipart message.
// Its contents may be either stored in memory or on disk.
// If stored on disk, the File's underlying concrete type will be an *os.File.
type File interface {
io.Reader
io.ReaderAt
io.Seeker
io.Closer
}
// A FileHeader describes a file part of a multipart request.
type FileHeader struct {
Filename string
Header textproto.MIMEHeader
Size int64
content []byte
tmpfile string
tmpoff int64
tmpshared bool
}
轻量级数据传输格式
总体上分为两种:
一种是JSONObject(json对象
{"key":value,"key":value}
一种时JSONArrayP(json数组),包含多个JSONObject
[{"key":value},{"key":value}]
key是string类型,value可以是string类型(值被双引导号包含),也可以是数值或布尔类型等,也可以是JSONObject类型或JSONArray类型
可以使用Go语言标准库中encoding/json包下的Marshal()或Unmarshal()把结构体对象转换成[]byte或把[]byte中信息写入到结构体对象中
属性的tag可以进行下面配置
// 字段被本包忽略
Field int `json:"-"`
// 字段在json里的键为"myName"
Field int `json:"myName"`
// 字段在json里的键位"myName"且如果字段为空值将在对象中省略掉
Field int `json:"myName,omitempty"`
// 字段在json里的键为"Field"(默认值),但如果字段为空值会跳过;注意前导的逗号
Field int `json:",omitempty"`
. | 任意字符(标志 s == true 时还包括换行符) |
---|---|
[xyz] | 字符族 |
[^xyz] | 反向字符族 |
\d | Perl 预定义字符族 |
\D | 反向 Perl 预定义字符族 |
[:alpha:] | ASCII 字符族 |
[:^alpha:] | 反向 ASCII 字符族 |
\p{H} | Unicode 字符族(单字符名),参见 unicode 包 |
\P{H} | 反向 Unicode 字符族(单字符名) |
\p{Greek} | Unicode 字符族(完整字符名) |
\P{Greek} | 反向 Unicode 字符族(完整字符名) |
组合:
表达式 | 含义 | |
---|---|---|
xy | 匹配 x 后接着匹配 y | |
x | y | 匹配 x 或 y(优先匹配 x) |
重复:
表达式 | 含义 |
---|---|
x* | 重复 >=0 次匹配 x,越多越好(优先重复匹配 x) |
x+ | 重复 >=1 次匹配 x,越多越好(优先重复匹配 x) |
x? | 0 或 1 次匹配 x,优先 1 次 |
x{n,m} | n 到 m 次匹配 x,越多越好(优先重复匹配 x) |
x{n,} | 重复 >=n 次匹配 x,越多越好(优先重复匹配 x) |
x{n} | 重复 n 次匹配 x |
x*? | 重复 >=0 次匹配 x,越少越好(优先跳出重复) |
x+? | 重复 >=1 次匹配 x,越少越好(优先跳出重复) |
x?? | 0 或 1 次匹配 x,优先 0 次 |
type Cookie struct {
Name string
Value string
Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires string // for reading cookies only
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
}