• 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
    ",name))
    40 
    41 }
    42 
    43 func submit(c *gin.Context){
    44     name := c.DefaultQuery("name", "lili")
    45     c.String(200,fmt.Sprintf("hello %s
    ",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
    ",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
    ",name))
    40 
    41 }
    42 
    43 func submit(c *gin.Context){
    44     name := c.DefaultQuery("name", "lili")
    45     c.String(200,fmt.Sprintf("hello %s
    ",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
    ",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){}
     
  • 相关阅读:
    .VC中的Attach和Detach
    virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
    用API OleLoadPicture通过IStream来加载JPG、GIF格式的图片
    .OnNcHitTest
    线性规划与网络流24题索引
    线性规划与网络流24题 17运输问题
    网络流24题 21最长k可重区间集问题
    网络流16数字梯形问题
    网络流24题 20深海机器人问题
    网络流24题 19负载平衡问题
  • 原文地址:https://www.cnblogs.com/chaoyangxu/p/12156385.html
Copyright © 2020-2023  润新知