├── .idea ├── .gitignore ├── go-web-zero.iml ├── modules.xml └── vcs.xml ├── go.mod ├── go.sum ├── img.png ├── img_1.png ├── img_10.png ├── img_11.png ├── img_12.png ├── img_13.png ├── img_14.png ├── img_15.png ├── img_16.png ├── img_17.png ├── img_18.png ├── img_19.png ├── img_2.png ├── img_20.png ├── img_21.png ├── img_22.png ├── img_23.png ├── img_24.png ├── img_25.png ├── img_26.png ├── img_27.png ├── img_28.png ├── img_29.png ├── img_3.png ├── img_30.png ├── img_31.png ├── img_32.png ├── img_33.png ├── img_34.png ├── img_35.png ├── img_36.png ├── img_37.png ├── img_38.png ├── img_39.png ├── img_4.png ├── img_40.png ├── img_41.png ├── img_42.png ├── img_43.png ├── img_44.png ├── img_45.png ├── img_46.png ├── img_47.png ├── img_5.png ├── img_6.png ├── img_7.png ├── img_8.png ├── img_9.png ├── p1 └── main.go ├── p10 ├── index.html └── main.go ├── p12 ├── main.go └── tmpl.html ├── p13 ├── main.go ├── t1.html ├── t2.html └── tmpl.html ├── p14 └── templates │ └── about.html ├── p18 └── main.go ├── p19 ├── main.go ├── model.go └── service.go ├── p2 └── main.go ├── p21 ├── about.html ├── controller │ ├── about.go │ ├── contact.go │ ├── controller.go │ └── home.go ├── home.html ├── layout.html └── main.go ├── p23 ├── main.go ├── middleware │ └── auth.go ├── test.html └── test.http ├── p24 └── main.go ├── p3 └── main.go ├── p5 ├── main.go └── test.http ├── p6 ├── img │ ├── img.png │ └── p6-1.png └── main.go ├── p7 ├── index.html └── main.go ├── p8 ├── index.html ├── main.go └── testloadfile.txt └── readme.md /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/go-web-zero.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module go-web-zero 2 | 3 | go 1.17 4 | 5 | require github.com/denisenkom/go-mssqldb v0.12.0 6 | 7 | require ( 8 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect 9 | github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect 10 | golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= 2 | github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= 3 | github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA= 7 | github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= 8 | github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= 9 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= 10 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 11 | github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4= 12 | github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= 13 | github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= 14 | github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= 15 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 18 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 19 | golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= 20 | golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 21 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 22 | golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 23 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 24 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 25 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 26 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 27 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 28 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 29 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 30 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 31 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 32 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 33 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 34 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 35 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 36 | -------------------------------------------------------------------------------- /img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img.png -------------------------------------------------------------------------------- /img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_1.png -------------------------------------------------------------------------------- /img_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_10.png -------------------------------------------------------------------------------- /img_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_11.png -------------------------------------------------------------------------------- /img_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_12.png -------------------------------------------------------------------------------- /img_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_13.png -------------------------------------------------------------------------------- /img_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_14.png -------------------------------------------------------------------------------- /img_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_15.png -------------------------------------------------------------------------------- /img_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_16.png -------------------------------------------------------------------------------- /img_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_17.png -------------------------------------------------------------------------------- /img_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_18.png -------------------------------------------------------------------------------- /img_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_19.png -------------------------------------------------------------------------------- /img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_2.png -------------------------------------------------------------------------------- /img_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_20.png -------------------------------------------------------------------------------- /img_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_21.png -------------------------------------------------------------------------------- /img_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_22.png -------------------------------------------------------------------------------- /img_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_23.png -------------------------------------------------------------------------------- /img_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_24.png -------------------------------------------------------------------------------- /img_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_25.png -------------------------------------------------------------------------------- /img_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_26.png -------------------------------------------------------------------------------- /img_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_27.png -------------------------------------------------------------------------------- /img_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_28.png -------------------------------------------------------------------------------- /img_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_29.png -------------------------------------------------------------------------------- /img_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_3.png -------------------------------------------------------------------------------- /img_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_30.png -------------------------------------------------------------------------------- /img_31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_31.png -------------------------------------------------------------------------------- /img_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_32.png -------------------------------------------------------------------------------- /img_33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_33.png -------------------------------------------------------------------------------- /img_34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_34.png -------------------------------------------------------------------------------- /img_35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_35.png -------------------------------------------------------------------------------- /img_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_36.png -------------------------------------------------------------------------------- /img_37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_37.png -------------------------------------------------------------------------------- /img_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_38.png -------------------------------------------------------------------------------- /img_39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_39.png -------------------------------------------------------------------------------- /img_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_4.png -------------------------------------------------------------------------------- /img_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_40.png -------------------------------------------------------------------------------- /img_41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_41.png -------------------------------------------------------------------------------- /img_42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_42.png -------------------------------------------------------------------------------- /img_43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_43.png -------------------------------------------------------------------------------- /img_44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_44.png -------------------------------------------------------------------------------- /img_45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_45.png -------------------------------------------------------------------------------- /img_46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_46.png -------------------------------------------------------------------------------- /img_47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_47.png -------------------------------------------------------------------------------- /img_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_5.png -------------------------------------------------------------------------------- /img_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_6.png -------------------------------------------------------------------------------- /img_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_7.png -------------------------------------------------------------------------------- /img_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_8.png -------------------------------------------------------------------------------- /img_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/img_9.png -------------------------------------------------------------------------------- /p1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net/http" 4 | 5 | func main() { 6 | // 调用适配器处理函数,两个参数,一个http地址,一个是hangler函数 7 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 8 | w.Write([]byte("hello go")) 9 | }) 10 | 11 | //设置web 服务器,俩个参数,一个监听地址port,一个handler,默认是nil, 采用多路复用mux 12 | http.ListenAndServe("localhost:8080", nil) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /p10/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Go web 6 | 7 | 8 | hello go go go world 9 | 10 | -------------------------------------------------------------------------------- /p10/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | ) 7 | 8 | func writeExample(w http.ResponseWriter, r *http.Request) { 9 | str := ` 10 | 11 | 12 | 13 | Go web 14 | 15 | 16 | hello go go go world 17 | 18 | ` 19 | 20 | w.Write([]byte(str)) // 把str 写入到body 里面, 需要类型转换 21 | } 22 | 23 | func headerExample(w http.ResponseWriter, r *http.Request) { 24 | w.Header().Set("Location", "http://baidu.com") 25 | // 必须调用前修改header 26 | w.WriteHeader(302) // 重定向302 27 | } 28 | 29 | type POST struct { 30 | User string 31 | Thread []string 32 | } 33 | 34 | func jsonExample(w http.ResponseWriter, r *http.Request) { 35 | w.Header().Set("Content-Type", "application/json") 36 | post := &POST{ 37 | User: "xxpkk", 38 | Thread: []string{"first", "second", "third"}, 39 | } 40 | json, _ := json.Marshal(post) 41 | w.Write(json) 42 | } 43 | 44 | func main() { 45 | 46 | server := http.Server{ 47 | Addr: "localhost:8080", 48 | } 49 | http.HandleFunc("/write", writeExample) 50 | http.HandleFunc("/redirect", headerExample) 51 | 52 | //json 案例 53 | http.HandleFunc("/json", jsonExample) 54 | server.ListenAndServe() 55 | 56 | } 57 | -------------------------------------------------------------------------------- /p12/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "html/template" 5 | "net/http" 6 | ) 7 | 8 | // 自定义的handler 9 | func process(w http.ResponseWriter, r *http.Request) { 10 | // 解析模板文件,相对路径 11 | t, _ := template.ParseFiles("tmpl.html") 12 | // 执行模板,传入数据,替换{{.}} 13 | t.Execute(w, "hello go go go go") 14 | } 15 | 16 | func main() { 17 | server := http.Server{ 18 | Addr: "localhost:8080", 19 | } 20 | http.HandleFunc("/test", process) 21 | server.ListenAndServe() 22 | } 23 | -------------------------------------------------------------------------------- /p12/tmpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test template 6 | 7 | 8 | 下面是模板输出的内容:
9 | {{ . }} 10 | 11 | -------------------------------------------------------------------------------- /p13/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "text/template" 6 | ) 7 | 8 | func main() { 9 | 10 | server := http.Server{ 11 | Addr: "localhost:8080", 12 | } 13 | http.HandleFunc("/process", process) 14 | server.ListenAndServe() 15 | 16 | } 17 | 18 | func process(w http.ResponseWriter, r *http.Request) { 19 | //解析1个模板 20 | t, _ := template.ParseFiles("tmpl.html") 21 | t.Execute(w, "hello go") 22 | ////等价于下面两句话 23 | //t := template.New("tmpl.html") 24 | //t, _ = t.ParseFiles("tmpl.html") 25 | 26 | //t1,_, := template.ParseGlob("*.html") 27 | 28 | //解析多个模板 29 | ts, _ := template.ParseFiles("t1.html", "t2.html") 30 | ts.ExecuteTemplate(w, "t2.html", "hello go t2") 31 | 32 | } 33 | -------------------------------------------------------------------------------- /p13/t1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test template 6 | 7 | 8 | 下面是模板输出的内容:
9 | {{ . }} 10 | 11 | -------------------------------------------------------------------------------- /p13/t2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test template 6 | 7 | 8 | 下面是模板输出的内容:
9 | {{ . }} 10 | 11 | -------------------------------------------------------------------------------- /p13/tmpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test template 6 | 7 | 8 | 下面是模板输出的内容:
9 | {{ . }} 10 | 11 | -------------------------------------------------------------------------------- /p14/templates/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | about 6 | 7 | 8 | 9 | this is about 10 | 11 | 12 | -------------------------------------------------------------------------------- /p18/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | "log" 8 | // 数据库驱动, _ 自我注册init 会自动调用。把包变成_ , 不会直接使用。 9 | //没有变量,不影响代码里面的逻辑 10 | _ "github.com/denisenkom/go-mssqldb" 11 | ) 12 | 13 | var db *sql.DB // 指向数据库 14 | func main() { 15 | // 连接字符串 16 | connStr := fmt.Sprintf("server=%s;user id = %s; "+ 17 | ""+ 18 | "password=%s;port=%d;database=%s;", 19 | server, user, password, port, database) 20 | fmt.Println(connStr) 21 | 22 | db, err := sql.Open("sqlserver", connStr) 23 | if err != nil { 24 | log.Fatalln(err.Error()) 25 | } 26 | ctx := context.Background() 27 | 28 | err = db.PingContext(ctx) 29 | if err != nil { 30 | log.Fatalln(err.Error()) 31 | } 32 | // 测试是否连接数据库 33 | fmt.Println("connected!") 34 | } 35 | 36 | const ( 37 | server = "xxxx.xxx" 38 | port = 1433 39 | user = "xxx" 40 | password = "123" 41 | database = "go-db" 42 | ) 43 | -------------------------------------------------------------------------------- /p19/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | "log" 8 | // 数据库驱动, _ 自我注册init 会自动调用。把包变成_ , 不会直接使用。 9 | //没有变量,不影响代码里面的逻辑 10 | _ "github.com/denisenkom/go-mssqldb" 11 | ) 12 | 13 | var db *sql.DB // 指向数据库 14 | func main() { 15 | // 连接字符串 16 | connStr := fmt.Sprintf("server=%s;user id = %s; "+ 17 | ""+ 18 | "password=%s;port=%d;database=%s;", 19 | server, user, password, port, database) 20 | fmt.Println(connStr) 21 | 22 | var err error 23 | // 这个db 需要是全局的,不能用:= 24 | db, err = sql.Open("sqlserver", connStr) 25 | if err != nil { 26 | log.Fatalln(err.Error()) 27 | } 28 | ctx := context.Background() 29 | 30 | err = db.PingContext(ctx) 31 | if err != nil { 32 | log.Fatalln(err.Error()) 33 | } 34 | // 测试是否连接数据库 35 | fmt.Println("connected!") 36 | 37 | // 查询 38 | one, err := getOne(103) 39 | if err != nil { 40 | log.Fatalln(err.Error()) 41 | } 42 | fmt.Println(one) 43 | } 44 | 45 | const ( 46 | server = "xxxx.xxx" 47 | port = 1433 48 | user = "xxx" 49 | password = "123" 50 | database = "go-db" 51 | ) 52 | -------------------------------------------------------------------------------- /p19/model.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 对应数据库的结构 4 | type app struct { 5 | ID int 6 | name string 7 | status int 8 | level int 9 | order int 10 | } 11 | -------------------------------------------------------------------------------- /p19/service.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "log" 6 | ) 7 | 8 | func getOne(id int) (a app, err error) { 9 | a = app{} 10 | 11 | // [order] 是sql里面的关键字,加上【】 12 | err = db.QueryRow("select id, name, status,"+ 13 | "level, [order] from dbo.App").Scan( 14 | &a.ID, &a.name, &a.status, &a.level, &a.order) 15 | return 16 | } 17 | 18 | // 返回的切片【】 19 | func getMany(id int) (apps []app, err error) { 20 | 21 | // [order] 是sql里面的关键字,加上【】 22 | rows, err := db.Query("select id, name, status,"+ 23 | "level, [order] from dbo.App where id > @id", sql.Named("Id", id)) 24 | 25 | //对rows 遍历 26 | 27 | for rows.Next() { 28 | a := app{} 29 | err = rows.Scan( 30 | &a.ID, &a.name, &a.status, &a.level, &a.order) 31 | if err != nil { 32 | log.Fatalln(err.Error()) 33 | } 34 | apps = append(apps, a) 35 | } 36 | return apps, err 37 | 38 | } 39 | -------------------------------------------------------------------------------- /p2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net/http" 4 | 5 | func main() { 6 | //mh := myHandler{} // 要使用的是这个指针 7 | //about := aboutHandler{} 8 | //hello := helloHandler{} 9 | 10 | //http.ListenAndServe("localhost:8080", nil) 11 | 12 | // 等价于上面一句话 13 | server := http.Server{ 14 | Addr: ("localhost:8080"), 15 | Handler: nil, 16 | //Handler: &mh, 17 | } 18 | // 不同路径对应不用handler 19 | //http.Handle("/hello", &hello) 20 | //http.Handle("/about", &about) 21 | //http.Handle("/home", &mh) 22 | 23 | http.HandleFunc("/welcome", welcomeExample) // 这个不能是welcomeExample() 24 | server.ListenAndServe() 25 | 26 | } 27 | 28 | // 自定义http.handleFunc 函数, 形参和handler函数一样 29 | func welcomeExample(w http.ResponseWriter, r *http.Request) { 30 | w.Write([]byte("welcome!")) 31 | } 32 | 33 | // 自定义handler, 实现ServerHTTP 方法 34 | type myHandler struct { 35 | } 36 | 37 | // 自定义handler, 实现ServerHTTP 方法 38 | type helloHandler struct { 39 | } 40 | 41 | type aboutHandler struct { 42 | } 43 | 44 | //ServeHTTP 不是ServerHTTP 45 | func (m *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 46 | w.Write([]byte("home handler")) 47 | } 48 | 49 | func (m *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 50 | w.Write([]byte("hello handler")) 51 | } 52 | func (m *aboutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 53 | w.Write([]byte("about handler")) 54 | } 55 | -------------------------------------------------------------------------------- /p21/about.html: -------------------------------------------------------------------------------- 1 | {{ define "content"}} 2 | 3 |

about: {{ . }}

4 | 5 | {{ end }} -------------------------------------------------------------------------------- /p21/controller/about.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "text/template" 7 | ) 8 | 9 | // 注册路由 10 | func registerAboutRoutes() { 11 | http.HandleFunc("/about", handleAbout) 12 | } 13 | 14 | // handle处理逻辑 15 | func handleAbout(w http.ResponseWriter, r *http.Request) { 16 | t, err := template.ParseFiles("p21/layout.html", "p21/about.html") 17 | // 服务器没有数据,需要判err, open layout.html: The system cannot find the file specified. 18 | if err != nil { 19 | fmt.Println(err) // Ugly debug output 20 | w.WriteHeader(http.StatusInternalServerError) // Proper HTTP response , HTTP ERROR 500 21 | return 22 | } 23 | t.ExecuteTemplate(w, "about", "hello world") 24 | } 25 | -------------------------------------------------------------------------------- /p21/controller/contact.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "text/template" 7 | ) 8 | 9 | // 注册路由 10 | func registerContactRoutes() { 11 | http.HandleFunc("/contact", handleContact) 12 | } 13 | 14 | // handle处理逻辑 15 | func handleContact(w http.ResponseWriter, r *http.Request) { 16 | t, err := template.ParseFiles("p21/layout.html", "p21/home.html") 17 | if err != nil { 18 | fmt.Printf("错误%v", err) // Ugly debug output 19 | w.WriteHeader(http.StatusInternalServerError) // Proper HTTP response 20 | return 21 | } 22 | t.ExecuteTemplate(w, "layout", "hello world") 23 | } 24 | -------------------------------------------------------------------------------- /p21/controller/controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | // 路由总的入口 4 | func RegisterRoutes() { 5 | 6 | // static resources 写这里 7 | 8 | registerHomeRoutes() 9 | registerAboutRoutes() 10 | registerContactRoutes() 11 | } 12 | -------------------------------------------------------------------------------- /p21/controller/home.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "text/template" 7 | ) 8 | 9 | // 注册路由 10 | func registerHomeRoutes() { 11 | http.HandleFunc("/home", handleHome) 12 | } 13 | 14 | // handle处理逻辑 15 | func handleHome(w http.ResponseWriter, r *http.Request) { 16 | t, e := template.ParseFiles("p21/layout.html", "p21/home.html") 17 | log.Println(e) 18 | t.ExecuteTemplate(w, "layout", "hello world") 19 | } 20 | -------------------------------------------------------------------------------- /p21/home.html: -------------------------------------------------------------------------------- 1 | {{ define "content"}} 2 | 3 |

Home: {{ . }}

4 | 5 | {{ end }} -------------------------------------------------------------------------------- /p21/layout.html: -------------------------------------------------------------------------------- 1 | {{ define "content"}} 2 | 3 |

layout: {{ . }}

4 | 5 | {{ end }} -------------------------------------------------------------------------------- /p21/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go-web-zero/p21/controller" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | 11 | /* 写在controller 里面 12 | http.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) { 13 | t, _ := template.ParseFiles("layout.html", "home.html") 14 | t.ExecuteTemplate(w, "layout", "hello world") 15 | }) 16 | 17 | http.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) { 18 | t, _ := template.ParseFiles("layout.html", "about.html") 19 | t.ExecuteTemplate(w, "layout", "hello world") 20 | }) 21 | 22 | http.HandleFunc("/contact", func(w http.ResponseWriter, r *http.Request) { 23 | t, e := template.ParseFiles("layout.html") 24 | t.ExecuteTemplate(w, "layout", "hello world") 25 | log.Println(e) 26 | }) 27 | */ 28 | fmt.Println("准备注册路由") 29 | controller.RegisterRoutes() // 注册路由,等价于上面的代码 30 | fmt.Println("已经注册路由") 31 | http.ListenAndServe("localhost:8080", nil) // 采用默认的多路复用器 32 | } 33 | 34 | // 问题,web 无任何内容??? 35 | -------------------------------------------------------------------------------- /p23/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "go-web-zero/p23/middleware" 6 | "net/http" 7 | ) 8 | 9 | type Company struct { 10 | ID int 11 | Name string 12 | Country string 13 | } 14 | 15 | func main() { 16 | http.HandleFunc("/companies", func(w http.ResponseWriter, r *http.Request) { 17 | c := Company{ 18 | ID: 123, 19 | Name: "gggoolle", 20 | Country: "USA", 21 | } 22 | enc := json.NewEncoder(w) 23 | enc.Encode(c) 24 | }) 25 | // 使用中间件 26 | http.ListenAndServe("localhost:8080", new(middleware.AuthMiddleware)) 27 | } 28 | -------------------------------------------------------------------------------- /p23/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import "net/http" 4 | 5 | // 链式结构, Next 设置为 什么,下一个handler 就是什么 6 | // AuthMiddleware .. 7 | type AuthMiddleware struct { 8 | Next http.Handler 9 | } 10 | 11 | func (am *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { 12 | // 如果只有一个中间件,改中间件的字段next 为nil, 交给默认路由器处理 13 | if am.Next == nil { 14 | 15 | am.Next = http.DefaultServeMux 16 | } 17 | // 判断auth 18 | auth := r.Header.Get("Authorization") 19 | if auth != "" { 20 | // before 路由 21 | am.Next.ServeHTTP(w, r) 22 | // after 路由 23 | } else { 24 | w.WriteHeader(http.StatusUnauthorized) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /p23/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /p23/test.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:8080/companies HTTP/1.1 2 | 3 | # with auth 4 | GET http://localhost:8080/companies HTTP/1.1 5 | Authorization: aadfsafds -------------------------------------------------------------------------------- /p24/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | fmt.Println("test tls") 9 | //http.ListenAndServeTLS("localhost:8080", nil, nil, nil) 10 | } 11 | -------------------------------------------------------------------------------- /p3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net/http" 4 | 5 | func main() { 6 | mh := myHandler{} // 要使用的是这个指针 7 | about := aboutHandler{} 8 | hello := helloHandler{} 9 | 10 | //http.ListenAndServe("localhost:8080", nil) 11 | 12 | // 等价于上面一句话 13 | server := http.Server{ 14 | Addr: ("localhost:8080"), 15 | Handler: nil, 16 | //Handler: &mh, 17 | } 18 | //不同路径对应不用handler 19 | http.Handle("/hello", &hello) 20 | http.Handle("/about", &about) 21 | http.Handle("/home", &mh) 22 | 23 | server.ListenAndServe() 24 | 25 | } 26 | 27 | // 自定义handler, 实现ServerHTTP 方法 28 | type myHandler struct { 29 | } 30 | 31 | // 自定义handler, 实现ServerHTTP 方法 32 | type helloHandler struct { 33 | } 34 | 35 | type aboutHandler struct { 36 | } 37 | 38 | //ServeHTTP 不是ServerHTTP 39 | func (m *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 40 | w.Write([]byte("home handler")) 41 | } 42 | 43 | func (m *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 44 | w.Write([]byte("hello handler")) 45 | } 46 | func (m *aboutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 47 | w.Write([]byte("about handler")) 48 | } 49 | -------------------------------------------------------------------------------- /p5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | server := http.Server{ 10 | Addr: "localhost:8080", 11 | Handler: nil, 12 | } 13 | 14 | http.HandleFunc("/post", func(w http.ResponseWriter, r *http.Request) { 15 | // 打印header 16 | fmt.Fprintln(w, r.Header) 17 | 18 | // 打印body 19 | length := r.ContentLength 20 | body := make([]byte, length) 21 | r.Body.Read(body) 22 | fmt.Fprintln(w, string(body)) // 结果写入到ResponseWrite 里面,需要转为字符串,才能看明白 23 | 24 | }) 25 | server.ListenAndServe() 26 | } 27 | -------------------------------------------------------------------------------- /p5/test.http: -------------------------------------------------------------------------------- 1 | 2 | # GET 3 | GET http://localhost:8080/header HTTP/1.1 4 | 5 | # POST test body 6 | POST http://localhost:8080/post HTTP/1.1 7 | content-type: application/json 8 | { 9 | "name":"sample" 10 | "time":"Wed, 21 Oct 2020 18:12:12 GMT" 11 | } -------------------------------------------------------------------------------- /p6/img/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/p6/img/img.png -------------------------------------------------------------------------------- /p6/img/p6-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkp58/go-web-zero/f1603f4ac140df4cc2b9c0fcb67b7535e04d840a/p6/img/p6-1.png -------------------------------------------------------------------------------- /p6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) { 10 | url := r.URL 11 | query := url.Query() 12 | 13 | // 方法1:通过map,返回字符串切片 14 | id := query["id"] 15 | log.Println(id) 16 | 17 | // 方法2:通过Get方法,返回key对应的第一个值 18 | name := query.Get("name") 19 | log.Println(name) 20 | 21 | }) 22 | http.ListenAndServe("localhost:8080", nil) 23 | } 24 | 25 | // 在浏览器输入:http://localhost:8080/home?id=001&name=xpk&id=002&name=zhuanma 26 | -------------------------------------------------------------------------------- /p7/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test Form 6 | 7 | 8 |
9 | first name 10 | 11 | last name 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /p7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | server := http.Server{ 10 | Addr: "localhost:8080", 11 | } 12 | http.HandleFunc("/process", func(w http.ResponseWriter, r *http.Request) { 13 | r.ParseForm() 14 | // r.Form 出现情况,url 里面的key 和 表单里面相同的话,会一起显示出来 15 | fmt.Fprintln(w, r.PostForm) 16 | }) 17 | server.ListenAndServe() 18 | } 19 | -------------------------------------------------------------------------------- /p8/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | load file 6 | 7 | 8 |
9 | first name 10 | 11 | last name 12 | 13 | file 14 | 15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /p8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | func process(w http.ResponseWriter, r *http.Request) { 10 | //r.ParseMultipartForm(1024) 11 | // 12 | //fileHeader := r.MultipartForm.File["uploaded"][0] // 获取上传的第一个文件 13 | //file, err := fileHeader.Open() 14 | 15 | file, _, err := r.FormFile("uploaded") // 传入的html form里面对应的key 16 | // 只会返回第一个文件,适合单文件上传 17 | if err == nil { 18 | data, err := ioutil.ReadAll(file) 19 | if err == nil { 20 | fmt.Fprintln(w, string(data)) 21 | } 22 | } 23 | 24 | } 25 | func main() { 26 | server := http.Server{ 27 | Addr: "localhost:8080", 28 | } 29 | http.HandleFunc("/process", process) 30 | server.ListenAndServe() 31 | } 32 | -------------------------------------------------------------------------------- /p8/testloadfile.txt: -------------------------------------------------------------------------------- 1 | 20220503 beijing 2 | xpengkang 3 | xxxx 4 | 5 | 6 | xxxx 7 | 8 | x 9 | xx 10 | xxxx 11 | xfs1242142141241 12 | 12124124 13 | 1241241 14 | 15 | 16 | 12412412 -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # go web zero(quickly start) 2 | 感谢up软件工艺师录制的go web 入门视频 3 | [source video](https://www.bilibili.com/video/BV1Xv411k7Xn?p=1) 4 | 5 |
6 | img_7.png 7 |
8 | 9 | 以下是我跟着学习记录的笔记及各个视频对应的源代码 10 | 11 | ## p1 demo 12 | 一个web 打印hello, 只需两行代码! 13 | code: 14 | ~~~go 15 | package main 16 | 17 | import "net/http" 18 | 19 | func main() { 20 | // 调用适配器处理函数,两个参数,一个http地址,一个是hangler函数 21 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 22 | w.Write([]byte("hello go")) 23 | }) 24 | 25 | //设置web 服务器,俩个参数,一个监听地址port,一个handler,默认是nil, 采用多路复用mux 26 | http.ListenAndServe("localhost:8080", nil) 27 | 28 | } 29 | ~~~ 30 | 31 | 浏览器运行截图 32 | 33 | ![img_33.png](img_33.png) 34 | 35 | ## p2 Handle 请求 上 36 | ~~~go 37 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 38 | w.Write([]byte("hello go")) 39 | }) 40 | ~~~ 41 | Handler 两个参数都是引用传递 42 | 43 | Handler Handler // handler to invoke, http.DefaultServeMux if nil 44 | 45 | 指针传递:w http.ResponseWriter, 46 | ResponseWriter是一个interface,代表了response的指针 47 | response是一个struct,他的指针实现了各种方法 48 | 指针传递:r *http.Request 49 | 50 | ![img_34.png](img_34.png) 51 | 52 | ![img_35.png](img_35.png) 53 | 54 | 源代码: 55 | http.Server 是一个struct 56 | 57 | ![img_36.png](img_36.png 58 | 59 | 60 | ~~~go 61 | http.ListenAndServe("localhost:8080", nil) 62 | ~~~ 63 | 我们可以自己定义server, 可配置方法:http.Server{} 64 | ~~~go 65 | // 等价于上面一句话 66 | server := http.Server{ 67 | Addr: ("localhost:8080"), 68 | Handler: nil, 69 | } 70 | server.ListenAndServe() 71 | ~~~ 72 | 73 | 理解Handler 74 | 75 | 1.这是一个接口 76 | 2.里面有ServeHTTP方法, 任何东西只要有这个方法就是Handler 77 | 78 | 3.DefaultServeMux 也是一个Handler 79 | 80 | ![img_37.png](img_37.png) 81 | 82 | 83 | code 84 | 85 | ~~~go 86 | package main 87 | 88 | import "net/http" 89 | 90 | func main() { 91 | mh := myHandler{} // 要使用的是这个指针 92 | 93 | //http.ListenAndServe("localhost:8080", nil) 94 | 95 | // 等价于上面一句话 96 | server := http.Server{ 97 | Addr: ("localhost:8080"), 98 | //Handler: nil, 99 | Handler: &mh, 100 | } 101 | server.ListenAndServe() 102 | 103 | } 104 | 105 | // 自定义handler, 实现ServerHTTP 方法 106 | type myHandler struct { 107 | } 108 | 109 | //ServeHTTP 不是ServerHTTP 110 | func (m *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 111 | w.Write([]byte("helllllllo my handler")) 112 | } 113 | ~~~ 114 | 115 | ![img_38.png](img_38.png) 116 | 117 | 118 | 119 | 120 | 121 | ## p3 Handle 请求 下 122 | 多个Hander 123 | 124 | 处理不同的路径/home, /about, /others 125 | 126 | ![img_39.png](img_39.png) 127 | 两个参数: 128 | 129 | 130 | // 不同路径对应不用handler 131 | http.Handle("/hello", &hello) 132 | http.Handle("/about", &about) 133 | http.Handle("/home", &mh) 134 | 135 | code 136 | ~~~go 137 | package main 138 | 139 | import "net/http" 140 | 141 | func main() { 142 | mh := myHandler{} // 要使用的是这个指针 143 | about := aboutHandler{} 144 | hello := helloHandler{} 145 | 146 | //http.ListenAndServe("localhost:8080", nil) 147 | 148 | // 等价于上面一句话 149 | server := http.Server{ 150 | Addr: ("localhost:8080"), 151 | Handler: nil, 152 | //Handler: &mh, 153 | } 154 | // 不同路径对应不用handler 155 | http.Handle("/hello", &hello) 156 | http.Handle("/about", &about) 157 | http.Handle("/home", &mh) 158 | server.ListenAndServe() 159 | 160 | } 161 | 162 | // 自定义handler, 实现ServerHTTP 方法 163 | type myHandler struct { 164 | } 165 | 166 | // 自定义handler, 实现ServerHTTP 方法 167 | type helloHandler struct { 168 | } 169 | 170 | type aboutHandler struct { 171 | } 172 | 173 | //ServeHTTP 不是ServerHTTP 174 | func (m *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 175 | w.Write([]byte("home handler")) 176 | } 177 | 178 | func (m *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 179 | w.Write([]byte("hello handler")) 180 | } 181 | func (m *aboutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 182 | w.Write([]byte("about handler")) 183 | } 184 | 185 | ~~~ 186 | 不同路径对应不用handler 187 | 188 | ![img_40.png](img_40.png) 189 | 190 | ![img_41.png](img_41.png) 191 | 192 | 第二个函数,http.HandleFunc 193 | 194 | ![img_42.png](img_42.png) 195 | 196 | code 197 | ~~~go 198 | 199 | package main 200 | 201 | import "net/http" 202 | 203 | func main() { 204 | 205 | server := http.Server{ 206 | Addr: ("localhost:8080"), 207 | Handler: nil, 208 | //Handler: &mh, 209 | } 210 | // 不同路径对应不用handler 211 | //http.Handle("/home", &mh) 212 | // 采用这个方法路由 213 | http.HandleFunc("/welcome", welcomeExample) // 这个不能是welcomeExample() 214 | server.ListenAndServe() 215 | 216 | } 217 | 218 | // 自定义http.handleFunc 函数, 形参和handler函数一样 219 | func welcomeExample(w http.ResponseWriter, r *http.Request) { 220 | w.Write([]byte("welcome!")) 221 | } 222 | ~~~ 223 | 224 | 225 | ![img_43.png](img_43.png) 226 | 227 | 228 | 总结:两个函数: 229 | 230 | ![img_44.png](img_44.png) 231 | 232 | http.Handle 第一个参数路由路径“/home” 233 | 第二个参数 Handler 234 | 235 | http.HandleFunc 第一个参数路由路径“/home” 236 | 第二个参数 Handler **函数**(http.HandleFunc **将Handler函数转换为Handler**) 237 | 238 | ## p4 内置的Handlers 239 | 240 | 5 个 241 | 242 | ![img_45.png](img_45.png) 243 | 244 | ## p5 Request 245 | Request 是一个struct, 表示请求消息 246 | 247 | 源码 248 | 249 | ![img_46.png](img_46.png) 250 | 251 | url 是一个包, URL 是一个struct 252 | ![img_47.png](img_47.png) 253 | 254 | 255 | ~~~go 256 | package main 257 | 258 | import ( 259 | "fmt" 260 | "net/http" 261 | ) 262 | 263 | func main() { 264 | server := http.Server{ 265 | Addr: "localhost:8080", 266 | Handler: nil, 267 | } 268 | 269 | http.HandleFunc("/post", func(w http.ResponseWriter, r *http.Request) { 270 | // 打印header 271 | fmt.Fprintln(w, r.Header) 272 | 273 | // 打印body 274 | length := r.ContentLength 275 | body := make([]byte, length) 276 | r.Body.Read(body) 277 | fmt.Fprintln(w, string(body)) // 结果写入到ResponseWrite 里面,需要转为字符串,才能看明白 278 | 279 | }) 280 | server.ListenAndServe() 281 | } 282 | ~~~ 283 | 284 | 285 | ## p6 286 | 287 | query 操作 288 | 方法1:通过map,返回字符串切片 289 | id := query["id"] 290 | 291 | 方法2:通过Get方法,返回key对应的第一个值 292 | name := query.Get("name") 293 | 294 | ~~~go 295 | package main 296 | 297 | import ( 298 | "log" 299 | "net/http" 300 | ) 301 | 302 | func main() { 303 | http.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) { 304 | url := r.URL 305 | query := url.Query() 306 | 307 | // 方法1:通过map,返回字符串切片 308 | id := query["id"] 309 | log.Println(id) 310 | 311 | // 方法2:通过Get方法,返回key对应的第一个值 312 | name := query.Get("name") 313 | log.Println(name) 314 | 315 | }) 316 | http.ListenAndServe("localhost:8080", nil) 317 | } 318 | ~~~ 319 | 320 | 321 | ## p7 322 | [source video](https://www.bilibili.com/video/BV1Xv411k7Xn?p=7) 323 | 324 | ![img_9.png](img_9.png) 325 | 326 | ~~~go 327 | package main 328 | 329 | import ( 330 | "fmt" 331 | "net/http" 332 | ) 333 | 334 | func main() { 335 | server := http.Server{ 336 | Addr: "localhost:8080", 337 | } 338 | http.HandleFunc("/process", func(w http.ResponseWriter, r *http.Request) { 339 | r.ParseForm() 340 | // r.Form 出现情况,url 里面的key 和 表单里面相同的话,会一起显示出来 341 | fmt.Fprintln(w, r.PostForm) 342 | }) 343 | server.ListenAndServe() 344 | } 345 | ~~~ 346 | 结果: 使用r.Form 347 | 348 | ![img_1.png](img_1.png) 349 | 350 | 结果:使用r.PostForm 351 | 352 | ![img_2.png](img_2.png) 353 | 354 | 355 | index.html 356 | ~~~html 357 | 358 | 359 | 360 | 361 | test Form 362 | 363 | 364 |
365 | first name 366 | 367 | last name 368 | 369 | 370 |
371 | 372 | 373 | 374 | ~~~ 375 | 376 | ## p8 上传文件 377 | 方法1 378 | 379 | ![img_3.png](img_3.png) 380 | 381 | 382 | 383 | ~~~go 384 | package main 385 | 386 | import ( 387 | "fmt" 388 | "io/ioutil" 389 | "net/http" 390 | ) 391 | 392 | func process(w http.ResponseWriter, r *http.Request) { 393 | r.ParseMultipartForm(1024) 394 | 395 | fileHeader := r.MultipartForm.File["uploaded"][0] // 获取上传的第一个文件 396 | file, err := fileHeader.Open() 397 | if err == nil { 398 | data, err := ioutil.ReadAll(file) 399 | if err == nil { 400 | fmt.Fprintln(w, string(data)) 401 | } 402 | } 403 | 404 | } 405 | func main() { 406 | server := http.Server{ 407 | Addr: "localhost:8080", 408 | } 409 | http.HandleFunc("/process", process) 410 | server.ListenAndServe() 411 | } 412 | ~~~ 413 | 414 | 415 | 成功读取文件 416 | 417 | ![img_5.png](img_5.png) 418 | 419 | 方法2 420 | 421 | ![img_4.png](img_4.png) 422 | 423 | ~~~go 424 | package main 425 | 426 | import ( 427 | "fmt" 428 | "io/ioutil" 429 | "net/http" 430 | ) 431 | 432 | func process(w http.ResponseWriter, r *http.Request) { 433 | //r.ParseMultipartForm(1024) 434 | // 435 | //fileHeader := r.MultipartForm.File["uploaded"][0] // 获取上传的第一个文件 436 | //file, err := fileHeader.Open() 437 | 438 | file, _, err := r.FormFile("uploaded") // 传入的html form里面对应的key 439 | // 只会返回第一个文件,适合单文件上传 440 | if err == nil { 441 | data, err := ioutil.ReadAll(file) 442 | if err == nil { 443 | fmt.Fprintln(w, string(data)) 444 | } 445 | } 446 | 447 | } 448 | func main() { 449 | server := http.Server{ 450 | Addr: "localhost:8080", 451 | } 452 | http.HandleFunc("/process", process) 453 | server.ListenAndServe() 454 | } 455 | ~~~ 456 | 457 | index.html 458 | ~~~html 459 | 460 | 461 | 462 | 463 | load file 464 | 465 | 466 |
467 | first name 468 | 469 | last name 470 | 471 | file 472 | 473 | 474 |
475 | 476 | 477 | 478 | ~~~ 479 | 480 | 解析JSON(视频里留坑,没有讲) 481 | 482 | ![img_6.png](img_6.png) 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | ## p9 492 | 无栗子 493 | 494 | ![img_10.png](img_10.png) 495 | 496 | ## p10 ResponseWriter 497 | 498 | ~~~go 499 | package main 500 | 501 | import "net/http" 502 | 503 | func writeExample(w http.ResponseWriter, r *http.Request) { 504 | str := ` 505 | 506 | 507 | 508 | Go web 509 | 510 | 511 | hello go go go world 512 | 513 | ` 514 | 515 | w.Write([]byte(str)) // 把str 写入到body 里面, 需要类型转换 516 | } 517 | func main() { 518 | 519 | server := http.Server{ 520 | Addr: "localhost:8080", 521 | } 522 | http.HandleFunc("/write", writeExample) 523 | server.ListenAndServe() 524 | 525 | } 526 | ~~~ 527 | 528 | 529 | 写入结果: 530 | 531 | img_11.png 532 | 533 | 534 | 535 | 536 | 537 | 538 | 写入json到web 里面 539 | 540 | ![img_12.png](img_12.png) 541 | 542 | 源代码: 543 | ~~~go 544 | package main 545 | 546 | import ( 547 | "encoding/json" 548 | "net/http" 549 | ) 550 | 551 | func writeExample(w http.ResponseWriter, r *http.Request) { 552 | str := ` 553 | 554 | 555 | 556 | Go web 557 | 558 | 559 | hello go go go world 560 | 561 | ` 562 | 563 | w.Write([]byte(str)) // 把str 写入到body 里面, 需要类型转换 564 | } 565 | 566 | func headerExample(w http.ResponseWriter, r *http.Request) { 567 | w.Header().Set("Location", "http://baidu.com") 568 | // 必须调用前修改header 569 | w.WriteHeader(302) // 重定向302 570 | } 571 | 572 | type POST struct { 573 | User string 574 | Thread []string 575 | } 576 | 577 | func jsonExample(w http.ResponseWriter, r *http.Request) { 578 | w.Header().Set("Content-Type", "application/json") 579 | post := &POST{ 580 | User: "xxpkk", 581 | Thread: []string{"first", "second", "third"}, 582 | } 583 | json, _ := json.Marshal(post) 584 | w.Write(json) 585 | } 586 | 587 | func main() { 588 | 589 | server := http.Server{ 590 | Addr: "localhost:8080", 591 | } 592 | http.HandleFunc("/write", writeExample) 593 | http.HandleFunc("/redirect", headerExample) 594 | 595 | //json 案例 596 | http.HandleFunc("/json", jsonExample) 597 | server.ListenAndServe() 598 | 599 | } 600 | ~~~ 601 | 602 | 603 | ## p11 内置的响应Response 604 | 605 | 606 | ## p12 模板 [video](https://www.bilibili.com/video/BV1Xv411k7Xn?p=12) 607 | 608 | ![img_13.png](img_13.png) 609 | 610 | 原理 611 | 612 | ![img_14.png](img_14.png) 613 | 614 | 课程代码 615 | ~~~go 616 | package main 617 | 618 | import ( 619 | "html/template" 620 | "net/http" 621 | ) 622 | 623 | // 自定义的handler 624 | func process(w http.ResponseWriter, r *http.Request) { 625 | // 解析模板文件,相对路径 626 | t, _ := template.ParseFiles("tmpl.html") 627 | // 执行模板,传入数据,替换{{.}} 628 | t.Execute(w, "hello go go go go") 629 | } 630 | 631 | func main() { 632 | server := http.Server{ 633 | Addr: "localhost:8080", 634 | } 635 | http.HandleFunc("/test", process) 636 | server.ListenAndServe() 637 | } 638 | ~~~ 639 | 640 | ## p13 641 | 642 | 源码解读: 643 | 644 | 解析模板源(可以是字符串或模板文件),从而创建一个解析好的模板的 struct 645 | 执行解析好的模板,并传入 ResponseWriter 和 数据。 646 | 这会触发模板引擎组合解析好的模板和数据,来产生最终的 HTML,并将它传递给 ResponseWriter 647 | 648 | ![img_15.png](img_15.png) 649 | 650 | 651 | code 652 | ~~~go 653 | package main 654 | 655 | import ( 656 | "html/template" 657 | "net/http" 658 | ) 659 | 660 | func main() { 661 | 662 | server := http.Server{ 663 | Addr: "localhost:8080", 664 | } 665 | http.HandleFunc("/process", process) 666 | server.ListenAndServe() 667 | 668 | } 669 | 670 | func process(w http.ResponseWriter, r *http.Request) { 671 | //解析1个模板 672 | t, _ := template.ParseFiles("tmpl.html") 673 | t.Execute(w, "hello go") 674 | ////等价于下面两句话 675 | //t := template.New("tmpl.html") 676 | //t, _ = t.ParseFiles("tmpl.html") 677 | 678 | //t1,_, := template.ParseGlob("*.html") 679 | 680 | //解析多个模板 681 | ts, _ := template.ParseFiles("t1.html", "t2.html") 682 | ts.ExecuteTemplate(w, "t2.html", "hello go t2") 683 | 684 | } 685 | 686 | ~~~ 687 | 688 | 689 | 690 | 691 | 执行出错 692 | 693 | ![img_16.png](img_16.png) 694 | 695 | ![img_17.png](img_17.png) 696 | 697 | 698 | ## p14 demo 模板执行与解析 699 | 700 | ## p18 链接数据库 701 | 702 | 连接到数据库 703 | 704 | 解决加载驱动问题,这里设置一下代理,就能正常下载github资源了 705 | 706 | ![img_19.png](img_19.png) 707 | 708 | [go代理](https://cloud.tencent.com/developer/article/1773630) 709 | 710 | func(*DB) pingContext 函数 711 | 712 | ![img_20.png](img_20.png) 713 | 714 | ~~~go 715 | package main 716 | 717 | import ( 718 | "context" 719 | "database/sql" 720 | "fmt" 721 | "log" 722 | // 数据库驱动, _ 自我注册init 会自动调用。把包变成_ , 不会直接使用。 723 | //没有变量,不影响代码里面的逻辑 724 | _ "github.com/denisenkom/go-mssqldb" 725 | ) 726 | 727 | var db *sql.DB // 指向数据库 728 | func main() { 729 | // 连接字符串 730 | connStr := fmt.Sprintf("server=%s;user id = %s; "+ 731 | ""+ 732 | "password=%s;port=%d;database=%s;", 733 | server, user, password, port, database) 734 | fmt.Println(connStr) 735 | 736 | db, err := sql.Open("sqlserver", connStr) 737 | if err != nil { 738 | log.Fatalln(err.Error()) 739 | } 740 | ctx := context.Background() 741 | 742 | err = db.PingContext(ctx) 743 | if err != nil { 744 | log.Fatalln(err.Error()) 745 | } 746 | // 测试是否连接数据库 747 | fmt.Println("connected!") 748 | } 749 | 750 | const ( 751 | server = "xxxx.xxx" 752 | port = 1433 753 | user = "xxx" 754 | password = "123" 755 | database = "go-db" 756 | ) 757 | ~~~ 758 | 759 | ## p19 数据库的查询 760 | 761 | ![img_21.png](img_21.png) 762 | 763 | 764 | 765 | main.go 766 | ~~~go 767 | package main 768 | 769 | import ( 770 | "context" 771 | "database/sql" 772 | "fmt" 773 | "log" 774 | // 数据库驱动, _ 自我注册init 会自动调用。把包变成_ , 不会直接使用。 775 | //没有变量,不影响代码里面的逻辑 776 | _ "github.com/denisenkom/go-mssqldb" 777 | ) 778 | 779 | var db *sql.DB // 指向数据库 780 | func main() { 781 | // 连接字符串 782 | connStr := fmt.Sprintf("server=%s;user id = %s; "+ 783 | ""+ 784 | "password=%s;port=%d;database=%s;", 785 | server, user, password, port, database) 786 | fmt.Println(connStr) 787 | 788 | var err error 789 | // 这个db 需要是全局的,不能用:= 790 | db, err = sql.Open("sqlserver", connStr) 791 | if err != nil { 792 | log.Fatalln(err.Error()) 793 | } 794 | ctx := context.Background() 795 | 796 | err = db.PingContext(ctx) 797 | if err != nil { 798 | log.Fatalln(err.Error()) 799 | } 800 | // 测试是否连接数据库 801 | fmt.Println("connected!") 802 | 803 | // 查询 804 | one, err := getOne(103) 805 | if err != nil { 806 | log.Fatalln(err.Error()) 807 | } 808 | fmt.Println(one) 809 | } 810 | 811 | const ( 812 | server = "xxxx.xxx" 813 | port = 1433 814 | user = "xxx" 815 | password = "123" 816 | database = "go-db" 817 | ) 818 | ~~~ 819 | 820 | 821 | model 对应数据库的结构 822 | ~~~go 823 | package main 824 | 825 | // 对应数据库的结构 826 | type app struct { 827 | ID int 828 | name string 829 | status int 830 | level int 831 | order int 832 | } 833 | ~~~ 834 | 835 | service :sql 语句 836 | ~~~go 837 | package main 838 | 839 | func getOne(id int) (a app, err error) { 840 | a = app{} 841 | 842 | // [order] 是sql里面的关键字,加上【】 843 | err = db.QueryRow("select id, name, status,"+ 844 | "level, [order] from dbo.App").Scan( 845 | &a.ID, &a.name, &a.status, &a.level, &a.order) 846 | return 847 | } 848 | ~~~ 849 | 850 | ## p20 crud 851 | 多行查询 852 | ~~~go 853 | // 返回的切片【】 854 | func getMany(id int) (apps []app, err error) { 855 | 856 | // [order] 是sql里面的关键字,加上【】 857 | rows, err := db.Query("select id, name, status,"+ 858 | "level, [order] from dbo.App where id > @id", sql.Named("Id", id)) 859 | 860 | //对rows 遍历 861 | 862 | for rows.Next() { 863 | a := app{} 864 | err = rows.Scan( 865 | &a.ID, &a.name, &a.status, &a.level, &a.order) 866 | if err != nil { 867 | log.Fatalln(err.Error()) 868 | } 869 | apps = append(apps, a) 870 | } 871 | return apps, err 872 | 873 | } 874 | ~~~ 875 | 876 | 877 | 878 | 879 | # p21 路由 880 | 881 | 针对不同的路径,使用不同的handler 882 | 883 | **之前的代码都在main 函数里面,不符合项目架构** 增加control 层 884 | 885 | main():设置类工作 886 | 887 | controller: 888 | 静态资源 889 | 把不同的请求送到不同的 controller 进行处理 890 | 891 | ![img_22.png](img_22.png) 892 | 893 | 894 | 895 | ## p22 896 | 897 | go 和json 属性映射 898 | 899 | ![img_24.png](img_24.png) 900 | 901 | ![img_25.png](img_25.png) 902 | 903 | 904 | 905 | ## p23 中间件 906 | 907 | ![img_26.png](img_26.png) 908 | 909 | 只要实现ServeHTTP 方法就可 910 | 911 | main.go 912 | ~~~go 913 | package main 914 | 915 | import ( 916 | "encoding/json" 917 | "go-web-zero/p23/middleware" 918 | "net/http" 919 | ) 920 | 921 | type Company struct { 922 | ID int 923 | Name string 924 | Country string 925 | } 926 | 927 | func main() { 928 | http.HandleFunc("/companies", func(w http.ResponseWriter, r *http.Request) { 929 | c := Company{ 930 | ID: 123, 931 | Name: "gggoolle", 932 | Country: "USA", 933 | } 934 | enc := json.NewEncoder(w) 935 | enc.Encode(c) 936 | }) 937 | // 使用中间件 938 | http.ListenAndServe("localhost:8080", new(middleware.AuthMiddleware)) 939 | } 940 | ~~~ 941 | 942 | auth.go 943 | ~~~go 944 | package middleware 945 | 946 | import "net/http" 947 | 948 | // 链式结构, Next 设置为 什么,下一个handler 就是什么 949 | // AuthMiddleware .. 950 | type AuthMiddleware struct { 951 | Next http.Handler 952 | } 953 | 954 | func (am *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { 955 | // 如果只有一个中间件,改中间件的字段next 为nil, 交给默认路由器处理 956 | if am.Next == nil { 957 | 958 | am.Next = http.DefaultServeMux 959 | } 960 | // 判断auth 961 | auth := r.Header.Get("Authorization") 962 | if auth != "" { 963 | // before 路由 964 | am.Next.ServeHTTP(w, r) 965 | // after 路由 966 | } else { 967 | w.WriteHeader(http.StatusUnauthorized) 968 | } 969 | } 970 | ~~~ 971 | 972 | 测试: 973 | ~~~html 974 | GET http://localhost:8080/companies HTTP/1.1 975 | 976 | # with auth 977 | GET http://localhost:8080/companies HTTP/1.1 978 | Authorization: aadfsafds 979 | ~~~ 980 | 981 | ![img_27.png](img_27.png) 982 | 983 | 984 | ## p25 https 985 | 986 | ![img_28.png](img_28.png) 987 | http.ListenAndServeTLS() 需要四个参数 988 | 989 | 990 | ## p27 测试 991 | 992 | ![img_29.png](img_29.png) 993 | 994 | ## p28 性能分析 995 | 996 | ![img_30.png](img_30.png) 997 | 998 | ![img_31.png](img_31.png) 999 | 1000 | ## p29 部署 1001 | Linux 部署 1002 | 1003 | ![img_32.png](img_32.png) 1004 | 1005 | 1006 | # p30 CRUD 栗子 1007 | 1008 | 1009 | # 完结撒花 1010 | 1011 | 都看到这里了,点个star吧:P 1012 | img_8.png 1013 | 1014 | 1015 | 1016 | 1017 | --------------------------------------------------------------------------------