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){}

 

 

 

 
posted @ 2020-01-06 15:05  chaoyangxu  阅读(3701)  评论(0编辑  收藏  举报