根据此视频整理
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){}