Gin学习笔记
Gin文档:https://pkg.go.dev/github.com/gin-gonic/gin
1、快速入门
1.1、安装Gin
go get -u github.com/gin-gonic/gin
1.2、main.go
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {// 创建路由引擎r := gin.Default()// 添加路由监听r.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Hello Gin!")})//启用 web 服务err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
2、配置热更新
Air文档:https://github.com/cosmtrek/air
2.1、下载
# 添加air包
go get -u github.com/cosmtrek/air
# 编译并安装air到 $GOPATH/bin 目录(重启一下Goland)
go install github.com/cosmtrek/air@latest
2.2、使用
# 直接使用air即可热加载
air
3、响应数据
3.1、String
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.LoadHTMLGlob("./template/*.html")r.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Hello Gin!")})r.GET("/hello", func(c *gin.Context) {//c.JSON(http.StatusOK, map[string]interface{}{// "name": "xumeng03",// "age": "24",//})c.JSON(http.StatusOK, gin.H{"name": "xumeng03","age": "24",})})r.GET("/gin", func(c *gin.Context) {c.HTML(http.StatusOK, "gin.html", gin.H{"path": c.FullPath(),})})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
3.2、JSON
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/hello", func(c *gin.Context) {//c.JSON(http.StatusOK, map[string]interface{}{// "name": "xumeng03",// "age": "24",//})c.JSON(http.StatusOK, gin.H{"name": "xumeng03","age": "24",})})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
3.3、HTML
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.LoadHTMLGlob("./template/*.html")r.GET("/gin", func(c *gin.Context) {c.HTML(http.StatusOK, "gin.html", gin.H{"path": c.FullPath(),})})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Gin Study</title>
</head>
<body>
<h1>Gin Study!</h1>
<p>请求路径:{{.path}}</p>
</body>
</html>
4、请求数据
4.1、Get
1、直接查询
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {// Query 查询 request 的参数,DefaultQuery 同样查询 request 的参数但若未查询到则赋一个默认值//var name = c.Query("name")var name = c.DefaultQuery("name", "Gin")c.String(http.StatusOK, "Hello %s!", name)})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
2、绑定到结构体
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {var person = Person{}err := c.ShouldBind(&person)if err != nil {c.JSON(http.StatusOK, gin.H{"status": 500,"message": "Params Error!",})return}c.JSON(http.StatusOK, gin.H{"status": 200,"data": person,})})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}type Person struct {Name string `json:"name" form:"name"`Age string `json:"age" form:"age"`
}
4.2、Post
1、直接查询
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.POST("/", func(c *gin.Context) {// PostForm 查询 request 的参数,DefaultPostForm 同样查询 request 的参数但若未查询到则赋一个默认值var name = c.PostForm("name")var age = c.DefaultPostForm("age", "20")c.String(http.StatusOK, "Hello %s %s!", name, age)})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
2、绑定到结构体(form-data)
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.POST("/", func(c *gin.Context) {var person = Person{}err := c.ShouldBind(&person)if err != nil {c.JSON(http.StatusOK, gin.H{"status": 500,})return}c.JSON(http.StatusOK, gin.H{"status": 500,"data": person,})})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}type Person struct {Name string `json:"name" form:"name"`Age string `json:"age" form:"age"`
}
3、绑定到结构体(json)
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.POST("/json", func(c *gin.Context) {var person = Person{}err := c.ShouldBindJSON(&person)if err != nil {c.JSON(http.StatusOK, gin.H{"status": 500,})return}c.JSON(http.StatusOK, gin.H{"status": 200,"data": person,})})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}type Person struct {Name string `json:"name" form:"name"`Age string `json:"age" form:"age"`
}
5、Restful
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/get/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello get %s!", param)})r.POST("/post/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello post %s!", param)})r.PUT("/put/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello put %s!", param)})r.DELETE("/delete/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello delete %s!", param)})err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
6、路由分组
6.1、基本使用
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()group := r.Group("/restful0"){group.GET("/get/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello get %s!", param)})group.POST("/post/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello post %s!", param)})}group1 := r.Group("/restful1"){group1.PUT("/put/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello put %s!", param)})group1.DELETE("/delete/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello delete %s!", param)})}err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
6.2、拆分文件
package mainimport ("ginstudy/router""github.com/gin-gonic/gin"
)func main() {r := gin.Default()router.Restful0(r)router.Restful1(r)err := r.Run()if err != nil {return} // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
package routerimport ("github.com/gin-gonic/gin""net/http"
)func Restful0(r *gin.Engine) {group := r.Group("/restful0"){group.GET("/get/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello get %s!", param)})group.POST("/post/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello post %s!", param)})}
}
package routerimport ("github.com/gin-gonic/gin""net/http"
)func Restful1(r *gin.Engine) {group1 := r.Group("/restful1"){group1.PUT("/put/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello put %s!", param)})group1.DELETE("/delete/:name", func(c *gin.Context) {param := c.Param("name")c.String(http.StatusOK, "Hello delete %s!", param)})}
}
7、自定义控制器
7.1、目录结构
7.2、router
app.go
package appimport ("ginstudy/controller/app""github.com/gin-gonic/gin"
)func AppApi(r *gin.Engine) {group := r.Group("/app/api")appController := app.AppController{}group.GET("/", appController.Index)
}
web.go
package webimport ("ginstudy/controller/web""github.com/gin-gonic/gin"
)func WebApi(r *gin.Engine) {group := r.Group("/web/api")webController := web.WebController{}group.GET("/", webController.Index)
}
7.3、controller
app.go
package appimport ("ginstudy/controller""github.com/gin-gonic/gin"
)type AppController struct {controller.StandardController
}func (app AppController) Index(c *gin.Context) {//c.String(http.StatusOK, "Hello App Api!")app.Success(c)
}
web.go
package webimport ("ginstudy/controller""github.com/gin-gonic/gin"
)type WebController struct {controller.StandardController
}func (web WebController) Index(c *gin.Context) {//c.String(http.StatusOK, "Hello Web Api!")web.Success(c)
}
standard.go
package controllerimport ("github.com/gin-gonic/gin""net/http"
)type StandardController struct{}func (standard StandardController) Success(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 200,})
}func (standard StandardController) Error(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 500,})
}
7.4、main
package mainimport ("ginstudy/router/app""ginstudy/router/web""github.com/gin-gonic/gin"
)func main() {r := gin.Default()app.AppApi(r)web.WebApi(r)err := r.Run()if err != nil {return}
}
7.5、go.mod
module ginstudygo 1.20require (dario.cat/mergo v1.0.0 // indirectgithub.com/bep/godartsass v1.2.0 // indirectgithub.com/bep/godartsass/v2 v2.0.0 // indirectgithub.com/bep/golibsass v1.1.1 // indirectgithub.com/bytedance/sonic v1.10.2 // indirectgithub.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirectgithub.com/chenzhuoyu/iasm v0.9.1 // indirectgithub.com/cli/safeexec v1.0.1 // indirectgithub.com/cosmtrek/air v1.49.0 // indirectgithub.com/creack/pty v1.1.20 // indirectgithub.com/fatih/color v1.15.0 // indirectgithub.com/fsnotify/fsnotify v1.7.0 // indirectgithub.com/gabriel-vasile/mimetype v1.4.3 // indirectgithub.com/gin-contrib/sse v0.1.0 // indirectgithub.com/gin-gonic/gin v1.9.1 // indirectgithub.com/go-playground/locales v0.14.1 // indirectgithub.com/go-playground/universal-translator v0.18.1 // indirectgithub.com/go-playground/validator/v10 v10.16.0 // indirectgithub.com/goccy/go-json v0.10.2 // indirectgithub.com/gohugoio/hugo v0.120.3 // indirectgithub.com/json-iterator/go v1.1.12 // indirectgithub.com/klauspost/cpuid/v2 v2.2.5 // indirectgithub.com/leodido/go-urn v1.2.4 // indirectgithub.com/mattn/go-colorable v0.1.13 // indirectgithub.com/mattn/go-isatty v0.0.20 // indirectgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirectgithub.com/modern-go/reflect2 v1.0.2 // indirectgithub.com/pelletier/go-toml v1.9.5 // indirectgithub.com/pelletier/go-toml/v2 v2.1.0 // indirectgithub.com/spf13/afero v1.10.0 // indirectgithub.com/tdewolff/parse/v2 v2.7.4 // indirectgithub.com/twitchyliquid64/golang-asm v0.15.1 // indirectgithub.com/ugorji/go/codec v1.2.11 // indirectgolang.org/x/arch v0.6.0 // indirectgolang.org/x/crypto v0.14.0 // indirectgolang.org/x/net v0.17.0 // indirectgolang.org/x/sys v0.14.0 // indirectgolang.org/x/text v0.14.0 // indirectgoogle.golang.org/protobuf v1.31.0 // indirectgopkg.in/yaml.v3 v3.0.1 // indirect
)
8、中间处理程序
8.1、基本使用
standard.go
package controllerimport ("fmt""github.com/gin-gonic/gin""net/http"
)type StandardController struct{}func (standard StandardController) Success(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 200,})
}func (standard StandardController) Error(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 500,})
}func (standard StandardController) Aop(c *gin.Context) {fmt.Println("aop start")// 放行请求c.Next()// 拒绝请求//c.Abort()fmt.Println("aop end")
}
web.go
package webimport ("ginstudy/controller/web""github.com/gin-gonic/gin"
)func WebApi(r *gin.Engine) {group := r.Group("/web/api")webController := web.WebController{}group.GET("/", webController.Aop, webController.Index)
}
app.go
package appimport ("ginstudy/controller/app""github.com/gin-gonic/gin"
)func AppApi(r *gin.Engine) {group := r.Group("/app/api")appController := app.AppController{}group.GET("/", appController.Aop, appController.Index)
}
8.2、多中间处理程序
standard.go
package controllerimport ("fmt""github.com/gin-gonic/gin""net/http"
)type StandardController struct{}func (standard StandardController) Success(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 200,})
}func (standard StandardController) Error(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 500,})
}func (standard StandardController) Aop1(c *gin.Context) {fmt.Println("aop1 start")// 放行请求c.Next()// 拒绝请求//c.Abort()fmt.Println("aop1 end")
}func (standard StandardController) Aop2(c *gin.Context) {fmt.Println("aop2 start")// 放行请求c.Next()// 拒绝请求//c.Abort()fmt.Println("aop2 end")
}
web.go
package webimport ("ginstudy/controller/web""github.com/gin-gonic/gin"
)func WebApi(r *gin.Engine) {group := r.Group("/web/api")webController := web.WebController{}group.GET("/", webController.Aop1, webController.Aop2, webController.Index)
}
app.go
package appimport ("ginstudy/controller/app""github.com/gin-gonic/gin"
)func AppApi(r *gin.Engine) {group := r.Group("/app/api")appController := app.AppController{}group.GET("/", appController.Aop1, appController.Aop2, appController.Index)
}
8.3、全局中间处理程序
路由组也可单独配置中间处理程序!
main.go
package mainimport ("ginstudy/controller""ginstudy/router/app""ginstudy/router/web""github.com/gin-gonic/gin"
)func main() {standardController := controller.StandardController{}r := gin.Default()r.Use(standardController.Aop1, standardController.Aop2)app.AppApi(r)web.WebApi(r)err := r.Run()if err != nil {return}
}
web.go
package webimport ("ginstudy/controller/web""github.com/gin-gonic/gin"
)func WebApi(r *gin.Engine) {group := r.Group("/web/api")webController := web.WebController{}group.GET("/", webController.Index)
}
app.go
package appimport ("ginstudy/controller/app""github.com/gin-gonic/gin"
)func AppApi(r *gin.Engine) {group := r.Group("/app/api")appController := app.AppController{}group.GET("/", appController.Index)
}
8.4、中间处理程序通信
standard.go
package controllerimport ("fmt""github.com/gin-gonic/gin""net/http"
)type StandardController struct{}func (standard StandardController) Success(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 200,})
}func (standard StandardController) Error(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 500,})
}func (standard StandardController) Aop1(c *gin.Context) {fmt.Println("aop1 start")c.Set("name", "xumeng03")// 放行请求c.Next()// 拒绝请求//c.Abort()fmt.Println("aop1 end")
}func (standard StandardController) Aop2(c *gin.Context) {fmt.Println("aop2 start")fmt.Println(c.Get("name"))// 放行请求c.Next()// 拒绝请求//c.Abort()fmt.Println("aop2 end")
}
8.5、协程中使用中间处理程序
standard.go
package controllerimport ("fmt""github.com/gin-gonic/gin""net/http""time"
)type StandardController struct{}func (standard StandardController) Success(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 200,})
}func (standard StandardController) Error(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": 500,})
}func (standard StandardController) Aop1(c *gin.Context) {fmt.Println("aop1 start")c.Set("name", "xumeng03")// 放行请求c.Next()// 拒绝请求//c.Abort()fmt.Println("aop1 end")
}func (standard StandardController) Aop2(c *gin.Context) {fmt.Println("aop2 start")fmt.Println(c.Get("name"))// 放行请求c.Next()// 拒绝请求//c.Abort()// 不能直接使用gin.Context,需要使用c.Copy()获取gin.Context的副本// c.Copy()只会复制gin.Context结构体中的字段值,并不会复制底层的请求和响应对象cc := c.Copy()go func() {time.Sleep(5 * time.Second)fmt.Println(cc.Request.URL.Path, "被访问了")}()fmt.Println("aop2 end")
}
9、自定义模块
package utilsimport "time"func UnixToDatetime(unix int64) string {return time.Unix(unix, 0).Format("2006-01-02 15:04:05")
}
10、文件上传
10.1、单文件上传
router/webgo
package webimport ("ginstudy/controller/web""github.com/gin-gonic/gin"
)func WebApi(r *gin.Engine) {group := r.Group("/web/api")webController := web.WebController{}group.GET("/", webController.Index)group.POST("/upload", webController.Upload)
}
controller/web.go
package webimport ("fmt""ginstudy/controller""github.com/gin-gonic/gin""path"
)type WebController struct {controller.StandardController
}func (web WebController) Index(c *gin.Context) {//c.String(http.StatusOK, "Hello Web Api!")fmt.Println("Hello Web Api!")web.Success(c)
}func (web WebController) Upload(c *gin.Context) {file, err := c.FormFile("file")if err != nil {fmt.Println("upload error!")}fmt.Println(file.Filename)// 路径为main.go所在目录p := path.Join("static", file.Filename)err = c.SaveUploadedFile(file, p)if err != nil {fmt.Println(err)return}web.Success(c)
}
10.2、多文件上传
router/webgo
package webimport ("ginstudy/controller/web""github.com/gin-gonic/gin"
)func WebApi(r *gin.Engine) {group := r.Group("/web/api")webController := web.WebController{}group.GET("/", webController.Index)group.POST("/uploads", webController.Uploads)
}
controller/web.go
package webimport ("fmt""ginstudy/controller""github.com/gin-gonic/gin""path"
)type WebController struct {controller.StandardController
}func (web WebController) Index(c *gin.Context) {//c.String(http.StatusOK, "Hello Web Api!")fmt.Println("Hello Web Api!")web.Success(c)
}func (web WebController) Uploads(c *gin.Context) {form, _ := c.MultipartForm()fmt.Println(form)files := form.File["files"]for k, file := range files {fmt.Println(k, file.Filename)p := path.Join("static", file.Filename)err := c.SaveUploadedFile(file, p)if err != nil {return}}web.Success(c)
}
11、Cookie&Session
11.1、cookie
package webimport ("fmt""ginstudy/controller""github.com/gin-gonic/gin""path"
)type WebController struct {controller.StandardController
}func (web WebController) Index(c *gin.Context) {//c.String(http.StatusOK, "Hello Web Api!")fmt.Println("Hello Web Api!")web.Success(c)
}func (web WebController) Cookie(c *gin.Context) {// name: cookie 名称// value: cookie 值// maxAge: 存活时间,单位秒(等于0则一直存活,小于0则删除cookie)// path: cookie 可用路径// domain: cookie 可用域名,如需在多个二级域名下共享,设置时需设置为“.bilibili.com”格式// secure: 是否只在 https 启用// httponly: cookie仅后端可操作cookie, err := c.Cookie("GinStudy")if err != nil {fmt.Println(err)}if cookie == "" {c.SetCookie("GinStudy", "xumeng03", 3600, "/", "localhost", false, false)}web.Success(c)
}
11.2、session
https://github.com/gin-contrib/sessions#redis
1、安装
go get github.com/gin-contrib/sessions
2、设置存储引擎
main.go
package mainimport ("ginstudy/router/app""ginstudy/router/web""github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/cookie""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 创建基于cookie的存储引擎store := cookie.NewStore([]byte("Ginstudy"))r.Use(sessions.Sessions("session", store))app.AppApi(r)web.WebApi(r)err := r.Run()if err != nil {return}
}
3、使用session
router/web.go
package webimport ("ginstudy/controller/web""github.com/gin-gonic/gin"
)func WebApi(r *gin.Engine) {group := r.Group("/web/api")webController := web.WebController{}group.GET("/", webController.Index)group.GET("/session", webController.Session)
}
controller/web.go
package webimport ("fmt""ginstudy/controller""github.com/gin-contrib/sessions""github.com/gin-gonic/gin""path"
)type WebController struct {controller.StandardController
}func (web WebController) Index(c *gin.Context) {//c.String(http.StatusOK, "Hello Web Api!")fmt.Println("Hello Web Api!")web.Success(c)
}func (web WebController) Session(c *gin.Context) {// 获取sessionsession := sessions.Default(c)name := session.Get("name")if name == nil {session.Set("name", "xumeng03")// 设置值(需要手动保存)session.Save()} else {fmt.Println(name)}web.Success(c)
}
11.3、分布式session
待补。。。