gin框架簡單使用


 

 

 

 

根據此視頻整理

https://www.bilibili.com/video/av73142413?p=9

 

 

 

下載

$ go get -u github.com/gin-gonic/gin

 

 

訪問

localhost:8080

 

 

案例1 : ping/pong 

 

 1 package main
 2 
 3 import "github.com/gin-gonic/gin"
 4 
 5 func main() {
 6     r := gin.Default()
 7     r.GET("/ping", func(c *gin.Context) {
 8         c.JSON(200, gin.H{
 9             "message": "pong",
10         })
11     })
12     r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
13 }

 

結果:

 

 

 

 

案例2:api 參數

 

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6 )
 7 
 8 func main() {
 9 
10     //1. 創建路由
11     r := gin.Default()
12 
13     //2. 綁定路由規則,api
14     r.GET("/user/:name/*action", func(c *gin.Context) {
15         name := c.Param("name")
16         action := c.Param("action")
17         c.String(http.StatusOK,name+" is "+action)
18 
19     })
20 
21     //3. 監聽
22     r.Run()
23 }

 

 

結果:

 

 

 

 

 

 

 

案例3:URL 參數

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6     "fmt"
 7 )
 8 
 9 func main() {
10 
11     //1. 創建路由
12     r := gin.Default()
13 
14     //2. 綁定路由規則,api
15     r.GET("/w", func(c *gin.Context) {
16 
17         ////第二個參數是默認數值
18         name := c.DefaultQuery("name", "xcy")
19         c.String(http.StatusOK,fmt.Sprintf("hello: %s",name))
20 
21     })
22 
23     //3. 監聽
24     r.Run()
25 }

 

 

結果:

 

 

 

 

 

 

 

案例4:表單傳值.

html

 1 cat src/page/login.html
 2 
 3 
 4 <!DOCTYPE html>
 5 <html lang="en">
 6 <head>
 7     <meta charset="UTF-8">
 8     <title>login</title>
 9 </head>
10 <body>
11 
12     <form action="http://127.0.0.1:8080/form" method="post" enctype="application/x-www-form-urlencoded">
13         User:<input type="text" name="username">
14         <br>
15         Pass:<input type="password" name="password" >
16         love:
17         <input type="checkbox" value="run"name="hobby">美女
18         <input type="checkbox" value="run"name="hobby">金錢
19          <input type="checkbox" value="run"name="hobby">游戲
20         <br>
21 
22         <input type="submit" value="Login">
23     </form>
24 
25 </body>
26 </html>

 

go

 

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "fmt"
 8 )
 9 
10 func main() {
11 
12     //1. 創建路由
13     r := gin.Default()
14 
15     //2.
16     r.POST("/form", func(c *gin.Context) {
17 
18         //表單參數設置默認值
19         type1 := c.DefaultPostForm("type", "alert")
20 
21         //接收username,password
22         username := c.PostForm("username")
23         password := c.PostForm("password")
24         //接收hobby
25         hobbys := c.PostFormArray("hobby")
26         c.String(200,
27             fmt.Sprintf("type is %s,username is %s,password is %s,hobby is %v",type1,username,password,hobbys))
28 
29     })
30 
31     //3. 監聽
32     r.Run()
33 }

 

 

 

結果:

 

 

 

 

 

 

 

案例5:上傳單個文件

 

html

 

cat src/page/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>

    <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data">
        頭像:
        <input type="file" name="file">
        <br>
        <input type="submit" value="commit">
    </form>

</body>
</html>

 

 

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "log"
 8     "fmt"
 9 )
10 
11 func main() {
12 
13     //1. 創建路由
14     r := gin.Default()
15 
16     
17     r.POST("/upload", func(c *gin.Context) {
18 
19         //表單取文件
20         file, _ := c.FormFile("file")
21         log.Println("aaa",file.Filename)
22 
23         //傳到項目到根目錄
24          c.SaveUploadedFile(file, file.Filename)
25          c.String(200,fmt.Sprintf("%s upload!",file.Filename))
26 
27     })
28 
29     //3. 監聽
30     r.Run()
31 }

 

 

 

結果:

 

 

 

 

 

 

 

案例6:上傳多個文件

 

html

 1 cat src/page/login.html
 2 
 3 <!DOCTYPE html>
 4 <html lang="en">
 5 <head>
 6     <meta charset="UTF-8">
 7     <title>login</title>
 8 </head>
 9 <body>
10 
11     <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data">
12         頭像:
13         <input type="file" name="files" multiple>
14         <br>
15         <input type="submit" value="commit">
16     </form>
17 
18 </body>
19 </html>

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8     "fmt"
 9 )
10 
11 func main() {
12 
13     //1. 創建路由
14     r := gin.Default()
15 
16     //限制表單上傳大小 8kb,defalut 32mb
17     r.MaxMultipartMemory = 8 << 20
18 
19     r.POST("/upload", func(c *gin.Context) {
20 
21         form, err := c.MultipartForm()
22         if err !=nil{
23             c.String(http.StatusBadRequest,fmt.Sprintf("get err %s",err.Error()))
24 
25             //獲取所有圖片
26             files := form.File["files"]
27             //遍歷所有圖片
28             for _,file := range files{
29                 //逐存儲
30                 if err :=c.SaveUploadedFile(file,file.Filename);err !=nil{
31                     c.String(http.StatusBadRequest,fmt.Sprintf("upload err %s",err.Error()))
32                     return
33                 }
34             }
35             c.String(200,fmt.Sprintf("upload ok %d files",len(files)))
36         }
37 
38     })
39 
40     //3. 監聽
41     r.Run()
42 }

 

 

 

結果:

 

 

 

 

 

 

案例7:路由組

 

go

 

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "fmt"
 8 )
 9 
10 func main() {
11 
12     //1. 創建路由
13     r := gin.Default()
14 
15 
16 
17 
18     //路由組1,處理get請求
19     v1 := r.Group("/v1")
20     {
21         v1.GET("/login",login)
22         v1.GET("submit",submit)
23     }
24 
25     //路由組2,處理post請求
26     v2 := r.Group("/v2")
27     {
28         v2.POST("/login",login)
29         v2.POST("submit",submit)
30     }
31 
32 
33     //3. 監聽
34     r.Run()
35 }
36 
37 func login(c *gin.Context){
38     name := c.DefaultQuery("name", "xcy")
39     c.String(200,fmt.Sprintf("hello %s\n",name))
40 
41 }
42 
43 func submit(c *gin.Context){
44     name := c.DefaultQuery("name", "lili")
45     c.String(200,fmt.Sprintf("hello %s\n",name))
46 
47 
48 }

 

 

結果:

 

 

 

 

案例8:json數據解析和綁定

 

go

 1 cat src/mian/mian.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8 )
 9 
10 //定義接收數據到結構體
11 type Login struct {
12     //binding裝飾到字段為必選字段,若接收為空值,則報錯
13     User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
14     Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
15 
16 }
17 
18 
19 
20 
21 func main() {
22 
23     //1. 創建路由
24     r := gin.Default()
25 
26     //json綁定
27     r.POST("loginJSON", func(c *gin.Context) {
28         //聲明接收的變量
29         var json Login
30 
31         //將request的body中數據,自動按照json格式解析到結構體
32 
33         if err := c.ShouldBindJSON(&json) ;err !=nil{
34             //返回錯誤信息
35 
36             //gin.H封裝了生成json數據工具
37             c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
38             return
39         }
40         //判斷用戶名密碼是否正確
41         if json.User != "root" || json.Password !="admin"{
42             c.JSON(http.StatusBadRequest,gin.H{"status":"304"})
43             return
44 
45         }
46         c.JSON(http.StatusOK,gin.H{"status":"200"})
47 
48     })
49 
50 
51     //3. 監聽
52     r.Run()
53 }

 

 

結果:

# curl http://127.0.0.1:8080/loginJSON -H 'content-type:application/json' -d "{\"user\":\"root\",\"password\":\"admin\"}"
{"status":"200"}
# curl http://127.0.0.1:8080/loginJSON -H 'content-type:application/json' -d "{\"user\":\"root\",\"password\":\"admin2\"}"
{"status":"304"}

 

 

 

 

 

 

 

 

案例9:表單數據解析和綁定

 

html

 1 cat src/page/login.html
 2 
 3 <!DOCTYPE html>
 4 <html lang="en">
 5 <head>
 6     <meta charset="UTF-8">
 7     <title>login</title>
 8 </head>
 9 <body>
10 
11    <form action="http://127.0.0.1:8080/form" method="post" enctype="application/x-www-form-urlencoded">
12     User:<input type="text" name="username">
13             <br>
14             Pass:<input type="password" name="password" >
15             love:
16             <input type="checkbox" value="run"name="hobby">美女
17              <input type="checkbox" value="run"name="hobby">金錢
18              <input type="checkbox" value="run"name="hobby">游戲
19             <br>
20 
21             <input type="submit" value="Login">
22         </form>
23 
24 </body>
25 </html>

 

 

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8 )
 9 
10 //定義接收數據到結構體
11 type Login struct {
12     //binding裝飾到字段為必選字段,若接收為空值,則報錯
13     User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
14     Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
15 
16 }
17 
18 
19 
20 
21 func main() {
22 
23     //1. 創建路由
24     r := gin.Default()
25 
26     //json綁定
27     r.POST("form", func(c *gin.Context) {
28         //聲明接收的變量
29         var form Login
30 
31         //Bind默認解析並綁定Bind,根據請求頭content-type自動推斷
32         if err := c.Bind(&form) ;err !=nil{
33             c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
34             return
35         }
36 
37 
38         //判斷用戶名密碼是否正確
39         if form.User != "root" || form.Password !="admin"{
40             c.JSON(http.StatusBadRequest,gin.H{"status":"304"})
41             return
42 
43         }
44         c.JSON(http.StatusOK,gin.H{"status":"200"})
45 
46     })
47 
48 
49     //3. 監聽
50     r.Run()
51 }

 

 

結果:

正確輸入

 

 

錯誤輸入

 

 

 

 

 

案例10:URL數據解析和綁定

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8 )
 9 
10 //定義接收數據到結構體
11 type Login struct {
12     //binding裝飾到字段為必選字段,若接收為空值,則報錯
13     User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
14     Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
15 
16 }
17 
18 
19 
20 
21 func main() {
22 
23     //1. 創建路由
24     r := gin.Default()
25 
26     //json綁定
27     r.GET("/:user/:password", func(c *gin.Context) {
28         //聲明接收的變量
29         var login Login
30 
31         if err := c.ShouldBindUri(&login) ;err !=nil{
32             c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
33             return
34         }
35 
36 
37         //判斷用戶名密碼是否正確
38         if login.User != "root" || login.Password !="admin"{
39             c.JSON(http.StatusBadRequest,gin.H{"status":"304"})
40             return
41 
42         }
43         c.JSON(http.StatusOK,gin.H{"status":"200"})
44 
45     })
46 
47 
48     //3. 監聽
49     r.Run()
50 }

 

 

 

結果:

root@xcy-virtual-machine:/data/goland/project/src/files# curl http://127.0.0.1:8080/root/admin
{"status":"200"}
root@xcy-virtual-machine:/data/goland/project/src/files# curl http://127.0.0.1:8080/root/admin2
{"status":"304"}

 

 

 

 

案例11 :多種響應方式 數據渲染

go

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "github.com/gin-gonic/gin/testdata/protoexample"
 6 )
 7 
 8 
 9 //多種響應方式
10 func main() {
11 
12     //創建路由
13     r := gin.Default()
14 
15     //1.json
16     r.GET("/somejson", func(c *gin.Context) {
17         c.JSON(200,gin.H{"message":"somejson","status":200})
18     })
19 
20 
21     //2.結構體響應
22     r.GET("somestruct", func(c *gin.Context) {
23         var msg struct{
24             Name string
25             Message string
26             Number int
27         }
28 
29         msg.Name="root"
30         msg.Message="message"
31         msg.Number=123
32 
33         c.JSON(200,msg)
34 
35     })
36 
37 
38     //3 xml
39     r.GET("somexml", func(c *gin.Context) {
40         c.XML(200,gin.H{"message":"xcy"})
41 
42     })
43 
44 
45     //4 YAml
46 
47     r.GET("someyaml", func(c *gin.Context) {
48         c.YAML(200,gin.H{"name":"yaml"})
49     })
50 
51 
52     // 5. protobuf格式,谷歌開發到高效存儲讀取的工具
53     r.GET("someprotobuf", func(c *gin.Context) {
54 
55         //定義數據
56         reps :=[]int64{int64(1),int64(2)}
57         lobel :="label"
58         data := &protoexample.Test{
59             Label:&lobel,
60             Reps:reps,
61 
62         }
63 
64         c.ProtoBuf(200,data)
65     })
66 
67 
68 
69     //3. 監聽
70     r.Run()
71 }

 

 

結果:

 

 

 

 

 

案例12: html渲染

html

 

cat src/templates/index.tmpl

<html>
    <h1>
        {{.title}}

    </h1>

</html>

 

 

 

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7 )
 8 
 9 
10 //多種響應方式
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15     //html渲染
16     //加載模板文件
17     //r.LoadHTMLFiles("templates/index.tmpl")
18     r.LoadHTMLGlob("templates/*")
19 
20     r.GET("/index", func(c *gin.Context) {
21 
22         //根據文件名渲染,最終json將title替換
23         c.HTML(200,"index.tmpl",gin.H{"title":"我的標簽"})
24 
25     })
26 
27 
28     //3. 監聽
29     r.Run()
30 }

 

 

 

 

結果:

 

 
        

 

 

 

案例13: 重定項 就是跳轉頁面

 

go

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6 )
 7 
 8 
 9 //多種響應方式
10 func main() {
11 
12     //創建路由
13     r := gin.Default()
14 
15     r.GET("/w", func(c *gin.Context) {
16 
17         //支持內部和外部重定向
18         c.Redirect(http.StatusMovedPermanently,"http://www.baidu.com")
19     })
20 
21 
22     //3. 監聽
23     r.Run()
24 }

 

結果:

輸入這個地址,自動跳轉到百度.

 

 

 

 

 

 

案例14:  異步請求

 

go

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "time"
 6     "log"
 7 )
 8 
 9 
10 //多種響應方式
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //1.異步
17     r.GET("/aysnc", func(c *gin.Context) {
18 
19         //不能直接使用c,需要使用一個副本,這是gin要求的
20         copycontext :=c.Copy()
21 
22         //異步處理
23         go func() {
24             time.Sleep(3*time.Second)
25             log.Println("異步: "+copycontext.Request.URL.Path)
26         }()
27     })
28 
2936 
37     //3. 監聽
38     r.Run()
39 }

 

 

結果:

 

同步請求,訪問瀏覽器后,會先sleep 3秒,服務器端才會響應200請求

 

 

 

 

 

異步請求,訪問瀏覽器后,服務器端直接響應 200請求

 

 

 

 

 

 

 

 

案例15: 全局中間件

 

 

 

 

 

 

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 
10 
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //注冊中間件
17     r.Use(MiddleWare())
18 
19     //{}為了代碼規范
20     {
21 
22            r.GET("/middleware", func(c *gin.Context) {
23                //.取值
24                req, _ := c.Get("request")
25                fmt.Println("request",req)
26 
27                //頁面接收
28                c.JSON(200,gin.H{"request":req})
29 
30            })
31 
32 
33     }
34 
35 
36 
37 
38 
39     //3. 監聽
40     r.Run()
41 }
42 
43 
44 
45 //定義中間件
46 func MiddleWare()gin.HandlerFunc{
47 
48     return func(c *gin.Context) {
49 
50         t := time.Now()
51 
52         fmt.Println("中間件開始執行了...")
53 
54         //設置變量到context中,可以通過get()取
55         c.Set("request","中間件")
56 
57         //執行函數
58         c.Next()
59        //中間件執行完后續到一些事情
60         status := c.Writer.Status()
61         fmt.Println("中間件執行完畢",status)
62 
63         t2 :=time.Since(t)
64 
65         fmt.Println("time",t2)
66 
67     }
68 }

 

 

 

 

結果

 

前端

 

后端

 

 

 

 

案例16: 局部中間件

單個請求加一個中間件

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 
10 
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //注冊中間件
17     r.Use(MiddleWare())
18 
19     //{}為了代碼規范
20     {
21 
22            r.GET("/middleware", func(c *gin.Context) {
23                //.取值
24                req, _ := c.Get("request")
25                fmt.Println("request",req)
26 
27                //頁面接收
28                c.JSON(200,gin.H{"request":req})
29 
30            })
31 
32            //單個到中間件,定義方法,根路由后面是定義局部中間件
33         r.GET("/middleware2",MiddleWare(), func(c *gin.Context) {
34             //.取值
35             req, _ := c.Get("request")
36             fmt.Println("request",req)
37 
38             //頁面接收
39             c.JSON(200,gin.H{"request":req})
40 
41         })
42 
43 
44     }
45 
46 
47 
48 
49 
50     //3. 監聽
51     r.Run()
52 }
53 
54 
55 
56 //定義中間件
57 func MiddleWare()gin.HandlerFunc{
58 
59     return func(c *gin.Context) {
60 
61         t := time.Now()
62 
63         fmt.Println("中間件開始執行了...")
64 
65         //設置變量到context中,可以通過get()取
66         c.Set("request","中間件")
67 
68         //執行中間件
69         c.Next()
70 
71         status := c.Writer.Status()
72         fmt.Println("中間件執行完畢",status)
73 
74         t2 :=time.Since(t)
75 
76         fmt.Println("time",t2)
77 
78     }
79 }

 

結果

 

 

 后台執行了兩邊,一個全局,一個單個

 

 

 

 

 

 

案例17:中間件練習

 

定義程序計時中間件,然后定義2個路由,執行函數后應該打印統計到執行時間。

如下:

 

 

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 
10 
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //注冊中間件
17     r.Use(myTime)
18 
19     //{}為了代碼規范
20     shoppinggroup := r.Group("/shopping")
21     {
22         shoppinggroup.GET("/index",shopindexhandler)
23         shoppinggroup.GET("/home",shophomehandler)
24 
25 
26 
27     }
28 
29     //監聽
30     r.Run()
31 }
32 
33 
34 
35 //定義中間件
36 func myTime(c *gin.Context){
37     start := time.Now()
38     c.Next()
39 
40     //統計時間
41     since := time.Since(start)
42     fmt.Println("程序用時:",since)
43 }
44 
45 
46 func shopindexhandler(c *gin.Context){
47     time.Sleep(5*time.Second)
48 }
49 
50 
51 func shophomehandler(c *gin.Context){
52     time.Sleep(5*time.Second)
53 }

 

結果:

前端

 

 

后端

 

 

 

 

 

 

 

 

案例18: 會話控制cookie

 

cookie流程

 

 

 

 

 

cookie使用

 

      測試服務端發送cookie給客戶端,客戶端請求時攜帶cookie

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6 )
 7 
 8 
 9 
10 func main() {
11 
12     //創建路由
13     r := gin.Default()
14 
15     //服務端要給客戶端cookie
16     r.GET("cookie", func(c *gin.Context) {
17 
18         //獲取客戶端是否攜帶cookie
19         cookie, err := c.Cookie("key")
20         if err !=nil{
21             cookie = "Notset"
22             //給客戶端設置cookie
23             //設置cookie
24             //maxAge 單位為秒
25             // path cookie所在目錄
26             // domain 域名 localhost
27             // secure 是否只能通過http訪問.
28             // httpOnly 是否允許別人通過json獲取自己到cookie
29             c.SetCookie("key","values",60,"/","localhost",false,true)
30         }
31         fmt.Printf("cookie的值是: %s\n",cookie)
32 
33         })
34 
35     //監聽
36     r.Run()
37 }

 

 

 

 

結果

 

 

 

 

 

 

 

 

 

 

 

 

cookie練習

 

 

 

 

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6 )
 7 
 8 
 9 
10 func main() {
11     //創建路由
12     r := gin.Default()
13 
14     r.GET("/login", func(c *gin.Context) {
15 
16         //設置cookie
17         c.SetCookie("abc","123",60,"/","localhost",false,true)
18 
19         //返回信息
20         c.String(200,"Login sucess!")
21     })
22 
23     r.GET("/home",AuthMiddleWare(), func(c *gin.Context) {
24 
25         c.JSON(200,gin.H{"data":"home"})
26     })
27 
28     //監聽
29     r.Run()
30 }
31 
32 
33 
34 
35 func AuthMiddleWare() gin.HandlerFunc{
36     return func(c *gin.Context) {
37 
38         //獲取客戶端cookie並且校驗
39         if cookie,err :=  c.Cookie("abc");err == nil{
40             if cookie == "123"{
41                 c.Next()
42                 return
43             }
44         }
45 
46         //返回錯誤
47         c.JSON(http.StatusUnauthorized,gin.H{"error":"err"})
48 
49         //如果驗證不通過,不再調用后續到函數處理.
50         c.Abort()
51         return
52     }
53 }

 

 

 

結果

 

第一次訪問home

 

 訪問login 模擬登錄

 

第二次訪問home,登錄到系統獲取數據

 

 

 

 

 

 

 

案例19: seesion會話

 

session原理

 

 

 

 

 

 

session中間件開發

 

設計一個通用的session服務,支持內存存儲和redis存儲

 

中間件原理圖

 

 

 

 

 

思路層面

session模塊設計

  本質上k-v系統,通過key進行增刪該查

  session可以存儲在內存和redis中,倆種都支持.

 

seesion接口設計

  set()

  get()

  del()

  slave()  redis 實現延遲加載

 

seesionMer接口設計

  Init()                 初始化,加載redis地址

  CreateSeesion()   創建一個新的seesion

  GetSession()        通過session獲取對應的session對象

 

實現層面
MemorySession設計

  定義MemorySession對象(字段:sessionid、存儲kv的map、讀寫鎖)

  構造函數 為了獲取對象

  set()

  get()

  del()

  slave()

  

MemorySessionMer設計

  定義MemorySessionMer對象(字段:存放所有session的map、讀寫鎖)

  構造函數

  Init()           

  CreateSeesion()  

  GetSession()    

     

 

RedisSession設計

  定義RedisSession對象(字段:sessionid、存儲kv的map、讀寫鎖,,redis連接池,記錄內存中map是否被修改的標記)

  構造函數

  set()  將session存到內存中map

  get()  取數據實現延遲加載

  del()

  slave()  將session存到redis

      

 

RedisSessionMer設計

  定義RedisSessionMer對象(字段:redis地址,redis密碼,連接池,讀寫鎖,大map)

  構造函數

  Init()           

  CreateSeesion()  

  GetSession()    

     

 

session

 1 cat src/session/session.go
 2 
 3 package session
 4 
 5 type Session interface {
 6     Set(key string,value interface{}) error
 7     Get(key string)(interface{},error)
 8     Del(key string) error
 9     Save() error
10 }

 

session mger

 1 cat src/session/sessionmgr.go
 2 
 3 package session
 4 
 5 //定義管理者,管理所有session
 6 type SessionMgr interface {
 7         
 8     //初始化
 9     Int(addr string,options ...string)(err error)
10     CreateSession()(session Session,err error)
11     Get(sessionId string) (session Session,err error)
12 }

 

memoryse

 

 

 

 

 

 

------------恢復內容結束------------

 

根據此視頻整理

https://www.bilibili.com/video/av73142413?p=9

 

 

 

下載

$ go get -u github.com/gin-gonic/gin

 

 

訪問

localhost:8080

 

 

案例1 : ping/pong 

 

 1 package main
 2 
 3 import "github.com/gin-gonic/gin"
 4 
 5 func main() {
 6     r := gin.Default()
 7     r.GET("/ping", func(c *gin.Context) {
 8         c.JSON(200, gin.H{
 9             "message": "pong",
10         })
11     })
12     r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
13 }

 

結果:

 

 

 

 

案例2:api 參數

 

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6 )
 7 
 8 func main() {
 9 
10     //1. 創建路由
11     r := gin.Default()
12 
13     //2. 綁定路由規則,api
14     r.GET("/user/:name/*action", func(c *gin.Context) {
15         name := c.Param("name")
16         action := c.Param("action")
17         c.String(http.StatusOK,name+" is "+action)
18 
19     })
20 
21     //3. 監聽
22     r.Run()
23 }

 

 

結果:

 

 

 

 

 

 

 

案例3:URL 參數

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6     "fmt"
 7 )
 8 
 9 func main() {
10 
11     //1. 創建路由
12     r := gin.Default()
13 
14     //2. 綁定路由規則,api
15     r.GET("/w", func(c *gin.Context) {
16 
17         ////第二個參數是默認數值
18         name := c.DefaultQuery("name", "xcy")
19         c.String(http.StatusOK,fmt.Sprintf("hello: %s",name))
20 
21     })
22 
23     //3. 監聽
24     r.Run()
25 }

 

 

結果:

 

 

 

 

 

 

 

案例4:表單傳值.

html

 1 cat src/page/login.html
 2 
 3 
 4 <!DOCTYPE html>
 5 <html lang="en">
 6 <head>
 7     <meta charset="UTF-8">
 8     <title>login</title>
 9 </head>
10 <body>
11 
12     <form action="http://127.0.0.1:8080/form" method="post" enctype="application/x-www-form-urlencoded">
13         User:<input type="text" name="username">
14         <br>
15         Pass:<input type="password" name="password" >
16         love:
17         <input type="checkbox" value="run"name="hobby">美女
18         <input type="checkbox" value="run"name="hobby">金錢
19          <input type="checkbox" value="run"name="hobby">游戲
20         <br>
21 
22         <input type="submit" value="Login">
23     </form>
24 
25 </body>
26 </html>

 

go

 

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "fmt"
 8 )
 9 
10 func main() {
11 
12     //1. 創建路由
13     r := gin.Default()
14 
15     //2.
16     r.POST("/form", func(c *gin.Context) {
17 
18         //表單參數設置默認值
19         type1 := c.DefaultPostForm("type", "alert")
20 
21         //接收username,password
22         username := c.PostForm("username")
23         password := c.PostForm("password")
24         //接收hobby
25         hobbys := c.PostFormArray("hobby")
26         c.String(200,
27             fmt.Sprintf("type is %s,username is %s,password is %s,hobby is %v",type1,username,password,hobbys))
28 
29     })
30 
31     //3. 監聽
32     r.Run()
33 }

 

 

 

結果:

 

 

 

 

 

 

 

案例5:上傳單個文件

 

html

 

cat src/page/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>

    <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data">
        頭像:
        <input type="file" name="file">
        <br>
        <input type="submit" value="commit">
    </form>

</body>
</html>

 

 

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "log"
 8     "fmt"
 9 )
10 
11 func main() {
12 
13     //1. 創建路由
14     r := gin.Default()
15 
16     
17     r.POST("/upload", func(c *gin.Context) {
18 
19         //表單取文件
20         file, _ := c.FormFile("file")
21         log.Println("aaa",file.Filename)
22 
23         //傳到項目到根目錄
24          c.SaveUploadedFile(file, file.Filename)
25          c.String(200,fmt.Sprintf("%s upload!",file.Filename))
26 
27     })
28 
29     //3. 監聽
30     r.Run()
31 }

 

 

 

結果:

 

 

 

 

 

 

 

案例6:上傳多個文件

 

html

 1 cat src/page/login.html
 2 
 3 <!DOCTYPE html>
 4 <html lang="en">
 5 <head>
 6     <meta charset="UTF-8">
 7     <title>login</title>
 8 </head>
 9 <body>
10 
11     <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data">
12         頭像:
13         <input type="file" name="files" multiple>
14         <br>
15         <input type="submit" value="commit">
16     </form>
17 
18 </body>
19 </html>

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8     "fmt"
 9 )
10 
11 func main() {
12 
13     //1. 創建路由
14     r := gin.Default()
15 
16     //限制表單上傳大小 8kb,defalut 32mb
17     r.MaxMultipartMemory = 8 << 20
18 
19     r.POST("/upload", func(c *gin.Context) {
20 
21         form, err := c.MultipartForm()
22         if err !=nil{
23             c.String(http.StatusBadRequest,fmt.Sprintf("get err %s",err.Error()))
24 
25             //獲取所有圖片
26             files := form.File["files"]
27             //遍歷所有圖片
28             for _,file := range files{
29                 //逐存儲
30                 if err :=c.SaveUploadedFile(file,file.Filename);err !=nil{
31                     c.String(http.StatusBadRequest,fmt.Sprintf("upload err %s",err.Error()))
32                     return
33                 }
34             }
35             c.String(200,fmt.Sprintf("upload ok %d files",len(files)))
36         }
37 
38     })
39 
40     //3. 監聽
41     r.Run()
42 }

 

 

 

結果:

 

 

 

 

 

 

案例7:路由組

 

go

 

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "fmt"
 8 )
 9 
10 func main() {
11 
12     //1. 創建路由
13     r := gin.Default()
14 
15 
16 
17 
18     //路由組1,處理get請求
19     v1 := r.Group("/v1")
20     {
21         v1.GET("/login",login)
22         v1.GET("submit",submit)
23     }
24 
25     //路由組2,處理post請求
26     v2 := r.Group("/v2")
27     {
28         v2.POST("/login",login)
29         v2.POST("submit",submit)
30     }
31 
32 
33     //3. 監聽
34     r.Run()
35 }
36 
37 func login(c *gin.Context){
38     name := c.DefaultQuery("name", "xcy")
39     c.String(200,fmt.Sprintf("hello %s\n",name))
40 
41 }
42 
43 func submit(c *gin.Context){
44     name := c.DefaultQuery("name", "lili")
45     c.String(200,fmt.Sprintf("hello %s\n",name))
46 
47 
48 }

 

 

結果:

 

 

 

 

案例8:json數據解析和綁定

 

go

 1 cat src/mian/mian.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8 )
 9 
10 //定義接收數據到結構體
11 type Login struct {
12     //binding裝飾到字段為必選字段,若接收為空值,則報錯
13     User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
14     Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
15 
16 }
17 
18 
19 
20 
21 func main() {
22 
23     //1. 創建路由
24     r := gin.Default()
25 
26     //json綁定
27     r.POST("loginJSON", func(c *gin.Context) {
28         //聲明接收的變量
29         var json Login
30 
31         //將request的body中數據,自動按照json格式解析到結構體
32 
33         if err := c.ShouldBindJSON(&json) ;err !=nil{
34             //返回錯誤信息
35 
36             //gin.H封裝了生成json數據工具
37             c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
38             return
39         }
40         //判斷用戶名密碼是否正確
41         if json.User != "root" || json.Password !="admin"{
42             c.JSON(http.StatusBadRequest,gin.H{"status":"304"})
43             return
44 
45         }
46         c.JSON(http.StatusOK,gin.H{"status":"200"})
47 
48     })
49 
50 
51     //3. 監聽
52     r.Run()
53 }

 

 

結果:

# curl http://127.0.0.1:8080/loginJSON -H 'content-type:application/json' -d "{\"user\":\"root\",\"password\":\"admin\"}"
{"status":"200"}
# curl http://127.0.0.1:8080/loginJSON -H 'content-type:application/json' -d "{\"user\":\"root\",\"password\":\"admin2\"}"
{"status":"304"}

 

 

 

 

 

 

 

 

案例9:表單數據解析和綁定

 

html

 1 cat src/page/login.html
 2 
 3 <!DOCTYPE html>
 4 <html lang="en">
 5 <head>
 6     <meta charset="UTF-8">
 7     <title>login</title>
 8 </head>
 9 <body>
10 
11    <form action="http://127.0.0.1:8080/form" method="post" enctype="application/x-www-form-urlencoded">
12     User:<input type="text" name="username">
13             <br>
14             Pass:<input type="password" name="password" >
15             love:
16             <input type="checkbox" value="run"name="hobby">美女
17              <input type="checkbox" value="run"name="hobby">金錢
18              <input type="checkbox" value="run"name="hobby">游戲
19             <br>
20 
21             <input type="submit" value="Login">
22         </form>
23 
24 </body>
25 </html>

 

 

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8 )
 9 
10 //定義接收數據到結構體
11 type Login struct {
12     //binding裝飾到字段為必選字段,若接收為空值,則報錯
13     User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
14     Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
15 
16 }
17 
18 
19 
20 
21 func main() {
22 
23     //1. 創建路由
24     r := gin.Default()
25 
26     //json綁定
27     r.POST("form", func(c *gin.Context) {
28         //聲明接收的變量
29         var form Login
30 
31         //Bind默認解析並綁定Bind,根據請求頭content-type自動推斷
32         if err := c.Bind(&form) ;err !=nil{
33             c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
34             return
35         }
36 
37 
38         //判斷用戶名密碼是否正確
39         if form.User != "root" || form.Password !="admin"{
40             c.JSON(http.StatusBadRequest,gin.H{"status":"304"})
41             return
42 
43         }
44         c.JSON(http.StatusOK,gin.H{"status":"200"})
45 
46     })
47 
48 
49     //3. 監聽
50     r.Run()
51 }

 

 

結果:

正確輸入

 

 

錯誤輸入

 

 

 

 

 

案例10:URL數據解析和綁定

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7     "net/http"
 8 )
 9 
10 //定義接收數據到結構體
11 type Login struct {
12     //binding裝飾到字段為必選字段,若接收為空值,則報錯
13     User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
14     Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
15 
16 }
17 
18 
19 
20 
21 func main() {
22 
23     //1. 創建路由
24     r := gin.Default()
25 
26     //json綁定
27     r.GET("/:user/:password", func(c *gin.Context) {
28         //聲明接收的變量
29         var login Login
30 
31         if err := c.ShouldBindUri(&login) ;err !=nil{
32             c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
33             return
34         }
35 
36 
37         //判斷用戶名密碼是否正確
38         if login.User != "root" || login.Password !="admin"{
39             c.JSON(http.StatusBadRequest,gin.H{"status":"304"})
40             return
41 
42         }
43         c.JSON(http.StatusOK,gin.H{"status":"200"})
44 
45     })
46 
47 
48     //3. 監聽
49     r.Run()
50 }

 

 

 

結果:

root@xcy-virtual-machine:/data/goland/project/src/files# curl http://127.0.0.1:8080/root/admin
{"status":"200"}
root@xcy-virtual-machine:/data/goland/project/src/files# curl http://127.0.0.1:8080/root/admin2
{"status":"304"}

 

 

 

 

案例11 :多種響應方式 數據渲染

go

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "github.com/gin-gonic/gin/testdata/protoexample"
 6 )
 7 
 8 
 9 //多種響應方式
10 func main() {
11 
12     //創建路由
13     r := gin.Default()
14 
15     //1.json
16     r.GET("/somejson", func(c *gin.Context) {
17         c.JSON(200,gin.H{"message":"somejson","status":200})
18     })
19 
20 
21     //2.結構體響應
22     r.GET("somestruct", func(c *gin.Context) {
23         var msg struct{
24             Name string
25             Message string
26             Number int
27         }
28 
29         msg.Name="root"
30         msg.Message="message"
31         msg.Number=123
32 
33         c.JSON(200,msg)
34 
35     })
36 
37 
38     //3 xml
39     r.GET("somexml", func(c *gin.Context) {
40         c.XML(200,gin.H{"message":"xcy"})
41 
42     })
43 
44 
45     //4 YAml
46 
47     r.GET("someyaml", func(c *gin.Context) {
48         c.YAML(200,gin.H{"name":"yaml"})
49     })
50 
51 
52     // 5. protobuf格式,谷歌開發到高效存儲讀取的工具
53     r.GET("someprotobuf", func(c *gin.Context) {
54 
55         //定義數據
56         reps :=[]int64{int64(1),int64(2)}
57         lobel :="label"
58         data := &protoexample.Test{
59             Label:&lobel,
60             Reps:reps,
61 
62         }
63 
64         c.ProtoBuf(200,data)
65     })
66 
67 
68 
69     //3. 監聽
70     r.Run()
71 }

 

 

結果:

 

 

 

 

 

案例12: html渲染

html

 

cat src/templates/index.tmpl

<html>
    <h1>
        {{.title}}

    </h1>

</html>

 

 

 

 

go

 1 cat src/main/main.go
 2 
 3 package main
 4 
 5 import (
 6     "github.com/gin-gonic/gin"
 7 )
 8 
 9 
10 //多種響應方式
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15     //html渲染
16     //加載模板文件
17     //r.LoadHTMLFiles("templates/index.tmpl")
18     r.LoadHTMLGlob("templates/*")
19 
20     r.GET("/index", func(c *gin.Context) {
21 
22         //根據文件名渲染,最終json將title替換
23         c.HTML(200,"index.tmpl",gin.H{"title":"我的標簽"})
24 
25     })
26 
27 
28     //3. 監聽
29     r.Run()
30 }

 

 

 

 

結果:

 

 
        

 

 

 

案例13: 重定項 就是跳轉頁面

 

go

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6 )
 7 
 8 
 9 //多種響應方式
10 func main() {
11 
12     //創建路由
13     r := gin.Default()
14 
15     r.GET("/w", func(c *gin.Context) {
16 
17         //支持內部和外部重定向
18         c.Redirect(http.StatusMovedPermanently,"http://www.baidu.com")
19     })
20 
21 
22     //3. 監聽
23     r.Run()
24 }

 

結果:

輸入這個地址,自動跳轉到百度.

 

 

 

 

 

 

案例14:  異步請求

 

go

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "time"
 6     "log"
 7 )
 8 
 9 
10 //多種響應方式
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //1.異步
17     r.GET("/aysnc", func(c *gin.Context) {
18 
19         //不能直接使用c,需要使用一個副本,這是gin要求的
20         copycontext :=c.Copy()
21 
22         //異步處理
23         go func() {
24             time.Sleep(3*time.Second)
25             log.Println("異步: "+copycontext.Request.URL.Path)
26         }()
27     })
28 
2936 
37     //3. 監聽
38     r.Run()
39 }

 

 

結果:

 

同步請求,訪問瀏覽器后,會先sleep 3秒,服務器端才會響應200請求

 

 

 

 

 

異步請求,訪問瀏覽器后,服務器端直接響應 200請求

 

 

 

 

 

 

 

 

案例15: 全局中間件

 

 

 

 

 

 

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 
10 
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //注冊中間件
17     r.Use(MiddleWare())
18 
19     //{}為了代碼規范
20     {
21 
22            r.GET("/middleware", func(c *gin.Context) {
23                //.取值
24                req, _ := c.Get("request")
25                fmt.Println("request",req)
26 
27                //頁面接收
28                c.JSON(200,gin.H{"request":req})
29 
30            })
31 
32 
33     }
34 
35 
36 
37 
38 
39     //3. 監聽
40     r.Run()
41 }
42 
43 
44 
45 //定義中間件
46 func MiddleWare()gin.HandlerFunc{
47 
48     return func(c *gin.Context) {
49 
50         t := time.Now()
51 
52         fmt.Println("中間件開始執行了...")
53 
54         //設置變量到context中,可以通過get()取
55         c.Set("request","中間件")
56 
57         //執行函數
58         c.Next()
59        //中間件執行完后續到一些事情
60         status := c.Writer.Status()
61         fmt.Println("中間件執行完畢",status)
62 
63         t2 :=time.Since(t)
64 
65         fmt.Println("time",t2)
66 
67     }
68 }

 

 

 

 

結果

 

前端

 

后端

 

 

 

 

案例16: 局部中間件

單個請求加一個中間件

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 
10 
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //注冊中間件
17     r.Use(MiddleWare())
18 
19     //{}為了代碼規范
20     {
21 
22            r.GET("/middleware", func(c *gin.Context) {
23                //.取值
24                req, _ := c.Get("request")
25                fmt.Println("request",req)
26 
27                //頁面接收
28                c.JSON(200,gin.H{"request":req})
29 
30            })
31 
32            //單個到中間件,定義方法,根路由后面是定義局部中間件
33         r.GET("/middleware2",MiddleWare(), func(c *gin.Context) {
34             //.取值
35             req, _ := c.Get("request")
36             fmt.Println("request",req)
37 
38             //頁面接收
39             c.JSON(200,gin.H{"request":req})
40 
41         })
42 
43 
44     }
45 
46 
47 
48 
49 
50     //3. 監聽
51     r.Run()
52 }
53 
54 
55 
56 //定義中間件
57 func MiddleWare()gin.HandlerFunc{
58 
59     return func(c *gin.Context) {
60 
61         t := time.Now()
62 
63         fmt.Println("中間件開始執行了...")
64 
65         //設置變量到context中,可以通過get()取
66         c.Set("request","中間件")
67 
68         //執行中間件
69         c.Next()
70 
71         status := c.Writer.Status()
72         fmt.Println("中間件執行完畢",status)
73 
74         t2 :=time.Since(t)
75 
76         fmt.Println("time",t2)
77 
78     }
79 }

 

結果

 

 

 后台執行了兩邊,一個全局,一個單個

 

 

 

 

 

 

案例17:中間件練習

 

定義程序計時中間件,然后定義2個路由,執行函數后應該打印統計到執行時間。

如下:

 

 

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 
10 
11 func main() {
12 
13     //創建路由
14     r := gin.Default()
15 
16     //注冊中間件
17     r.Use(myTime)
18 
19     //{}為了代碼規范
20     shoppinggroup := r.Group("/shopping")
21     {
22         shoppinggroup.GET("/index",shopindexhandler)
23         shoppinggroup.GET("/home",shophomehandler)
24 
25 
26 
27     }
28 
29     //監聽
30     r.Run()
31 }
32 
33 
34 
35 //定義中間件
36 func myTime(c *gin.Context){
37     start := time.Now()
38     c.Next()
39 
40     //統計時間
41     since := time.Since(start)
42     fmt.Println("程序用時:",since)
43 }
44 
45 
46 func shopindexhandler(c *gin.Context){
47     time.Sleep(5*time.Second)
48 }
49 
50 
51 func shophomehandler(c *gin.Context){
52     time.Sleep(5*time.Second)
53 }

 

結果:

前端

 

 

后端

 

 

 

 

 

 

 

 

案例18: 會話控制cookie

 

cookie流程

 

 

 

 

 

cookie使用

 

      測試服務端發送cookie給客戶端,客戶端請求時攜帶cookie

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "fmt"
 6 )
 7 
 8 
 9 
10 func main() {
11 
12     //創建路由
13     r := gin.Default()
14 
15     //服務端要給客戶端cookie
16     r.GET("cookie", func(c *gin.Context) {
17 
18         //獲取客戶端是否攜帶cookie
19         cookie, err := c.Cookie("key")
20         if err !=nil{
21             cookie = "Notset"
22             //給客戶端設置cookie
23             //設置cookie
24             //maxAge 單位為秒
25             // path cookie所在目錄
26             // domain 域名 localhost
27             // secure 是否只能通過http訪問.
28             // httpOnly 是否允許別人通過json獲取自己到cookie
29             c.SetCookie("key","values",60,"/","localhost",false,true)
30         }
31         fmt.Printf("cookie的值是: %s\n",cookie)
32 
33         })
34 
35     //監聽
36     r.Run()
37 }

 

 

 

 

結果

 

 

 

 

 

 

 

 

 

 

 

 

cookie練習

 

 

 

 

 

go

 

 1 package main
 2 
 3 import (
 4     "github.com/gin-gonic/gin"
 5     "net/http"
 6 )
 7 
 8 
 9 
10 func main() {
11     //創建路由
12     r := gin.Default()
13 
14     r.GET("/login", func(c *gin.Context) {
15 
16         //設置cookie
17         c.SetCookie("abc","123",60,"/","localhost",false,true)
18 
19         //返回信息
20         c.String(200,"Login sucess!")
21     })
22 
23     r.GET("/home",AuthMiddleWare(), func(c *gin.Context) {
24 
25         c.JSON(200,gin.H{"data":"home"})
26     })
27 
28     //監聽
29     r.Run()
30 }
31 
32 
33 
34 
35 func AuthMiddleWare() gin.HandlerFunc{
36     return func(c *gin.Context) {
37 
38         //獲取客戶端cookie並且校驗
39         if cookie,err :=  c.Cookie("abc");err == nil{
40             if cookie == "123"{
41                 c.Next()
42                 return
43             }
44         }
45 
46         //返回錯誤
47         c.JSON(http.StatusUnauthorized,gin.H{"error":"err"})
48 
49         //如果驗證不通過,不再調用后續到函數處理.
50         c.Abort()
51         return
52     }
53 }

 

 

 

結果

 

第一次訪問home

 

 訪問login 模擬登錄

 

第二次訪問home,登錄到系統獲取數據

 

 

案例19: gin數據庫

 

數據庫練習 

實現一個簡易的圖書管理系統,數據從mysql中讀取,書籍有id,title,price三個字段。

 

 

 

 

 

 html

展示內面

 1 cat src/book/templates/book_list.html
 2 
 3 {{define "book_list.html"}}
 4 
 5 <!DOCTYPE html>
 6 <html lang="en">
 7 <head>
 8     <meta charset="UTF-8">
 9     <title>書籍列表</title>
10 
11 </head>
12 <body>
13 <div><a href="/book/new">添加新書</a></div>
14   <table border="1">
15       <thead>
16       <tr>
17           <th>ID</th>
18             <th>title</th>
19             <th>price</th>
20              <th>exec</th>
21       </tr>
22       </thead>
23       <tbody>
24             {{range .data}}}
25                     <tr>
26                         <td>{{.ID}}} </td>
27                         <td>{{.Title}}} </td>
28                         <td>{{.Price}}} </td>
29                         <td><a href="/book/delete>id={{.ID}}} "> delete</a></td>
30                     </tr>
31                     {{end}}}
32       </tbody>
33 
34   </table>
35 
36 
37 </body>
38 </html>
39 
40 {{end}}}

 

 新增頁面

 1 cat src/book/templates/new_book.html
 2 
 3 {{define "book_list.html"}}
 4 
 5 <!DOCTYPE html>
 6 <html lang="en">
 7 <head>
 8     <meta charset="UTF-8">
 9     <title>添加圖書信息</title>
10 
11 </head>
12 <body>
13 <form action="/book/new" method="POST">
14 
15     <div>
16 
17         <label> 書名:
18             <input type="text" name="title">
19         </label>
20     </div>
21 
22     <div>
23 
24         <label> 價格:
25             <input type="number" name="price">
26         </label>
27     </div>
28 
29     <div>
30 
31             <input type="submit" value="commit">
32     </div>
33 
34 
35 
36 </form>
37 </body>
38 </html>
39 
40 
41 {{end}}}

 

 

 

 

 

 

 

案例20: seesion會話

 

session原理

 

 

 

 

 

 

session中間件開發

 

設計一個通用的session服務,支持內存存儲和redis存儲

 

中間件原理突

 

 

思路層面

session模塊設計

  本質上k-v系統,通過key進行增刪該查

  session可以存儲在內存和redis中,倆種都支持.

 

seesion接口設計

  set()

  get()

  del()

  slave()  redis 實現延遲加載

 

seesionMer接口設計

  Init()                 初始化,加載redis地址

  CreateSeesion()   創建一個新的seesion

  GetSession()        通過session獲取對應的session對象

 

實現層面
MemorySession設計

  定義MemorySession對象(字段:sessionid、存儲kv的map、讀寫鎖)

  構造函數 為了獲取對象

  set()

  get()

  del()

  slave()

  

MemorySessionMer設計

  定義MemorySessionMer對象(字段:存放所有session的map、讀寫鎖)

  構造函數

  Init()           

  CreateSeesion()  

  GetSession()    

     

 

RedisSession設計

  定義RedisSession對象(字段:sessionid、存儲kv的map、讀寫鎖,,redis連接池,記錄內存中map是否被修改的標記)

  構造函數

  set()  將session存到內存中map

  get()  取數據實現延遲加載

  del()

  slave()  將session存到redis

      

 

RedisSessionMer設計

  定義RedisSessionMer對象(字段:redis地址,redis密碼,連接池,讀寫鎖,大map)

  構造函數

  Init()           

  CreateSeesion()  

  GetSession()    

     

 

 session

cat src/session/session.go

package session

type Session interface {
    Set(key string,value interface{}) error
    Get(key string)(interface{},error)
    Del(key string) error
    Save() error
}

 

session mgr

 1 cat src/session/sessionmgr.go
 2 
 3 package session
 4 
 5 //定義管理者,管理所有session
 6 type SessionMgr interface {
 7 
 8     //初始化
 9     Int(addr string,options ...string)(err error)
10     CreateSession()(session Session,err error)
11     Get(sessionId string) (session Session,err error)
12 }

 

 memory session

 1 cat src/session/memory.go
 2 
 3 package session
 4 
 5 import (
 6     "sync"
 7     "errors"
 8 )
 9 
10 //MemorySession設計
11 //
12 //  定義MemorySession對象(字段:sessionid、存儲kv的map、讀寫鎖)
13 //
14 //  構造函數 為了獲取對象
15 //
16 //  set()
17 //
18 //  get()
19 //
20 //  del()
21 //
22 //  slave() 
23 
24 type MemorySession struct {
25     sessionId string
26     data map[string]interface{} //k,v
27     rwlock sync.RWMutex
28     
29 }
30 
31 //  構造函數 為了獲取對象
32 func NewMemorySession(id string) *MemorySession{
33     s := &MemorySession{
34         sessionId:id,
35         data:make(map[string]interface{},16),
36     }
37     return s
38 }
39 
40 
41 
42 //Set
43 func (m *MemorySession)Set(key string,value interface{})(err error){
44     //add lock
45     m.rwlock.Lock()
46     defer m.rwlock.Unlock()
47     
48     //設置值
49     m.data[key] = value
50     
51     return 
52 }
53 
54 //Get
55 func (m *MemorySession)Get(key string,value interface{})(err error){
56     //add lock
57     m.rwlock.Lock()
58     defer m.rwlock.Unlock()
59 
60     //設置值
61     value,ok := m.data[key]
62     if !ok{
63         err = errors.New("key not exists in session!")
64         return 
65     }
66 
67     return
68 }
69 
70 
71 
72 //  del()
73 func (m *MemorySession)Del(key string)(err error){
74     //add lock
75     m.rwlock.Lock()
76     defer m.rwlock.Unlock()
77 
78     delete(m.data,key)
79     return 
80 }
81 
82 
83 //  slave() 
84 func (m *MemorySession)Save(key string)(err error){
85     return 
86 }

 

 

 

 memory session mgr

 1 cat src/session/sessionmemorymgr.go
 2 //代碼有些問題
 3 
 4 package session
 5 
 6 import (
 7     "sync"
 8     uuid "github.com/satori/go.uuid"
 9     )
10 
11 //MemorySessionMer設計
12 //
13 //  定義MemorySessionMer對象(字段:存放所有session的map、讀寫鎖)
14 //
15 //  構造函數
16 //
17 //  Init()  
18 //
19 //  CreateSeesion()
20 //
21 //  GetSession()
22 
23 
24 //定義對象
25 type MemorySessionMgr struct {
26     sessionMap map[string]Session
27     rwlock sync.RWMutex
28 }
29 
30 //構造函數
31 func NewMemorySessionMer() SessionMgr{
32     sr := &MemorySessionMgr{
33         sessionMap:make(map[string]Session,1024),
34     }
35     return sr
36 }
37 
38 //  Init()  
39 func (s *MemorySessionMgr)Init(addr string,options ...string)(err error){
40     return
41 }
42 
43 
44 //  CreateSeesion()
45 func (s *MemorySessionMgr)CreateSeesion()(session Session,err error){
46         s.rwlock.Lock()
47     defer s.rwlock.Unlock()
48 
49     //go get github.com/satori/go.uuid
50     //用uuid作為session id
51     id, err := uuid.NewV4()
52     if err !=nil{
53         return
54     }
55     //轉string
56     sessionId := id.String()
57 
58     //創建session
59     session = NewMemorySession(sessionId)
60 
61 
62 
63 }
64 
65 //  GetSession()
66 
67 func (s *MemorySessionMgr)Get(sessionId string)(session Session,err error){}

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM