介绍
- Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点
- 对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错
- 借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范
安装
1.安装Gin go get -u github.com/gin-gonic/gin 2.引入包 import "github.com/gin-gonic/gin" 3.(可选)导入net/http。例如,如果使用常量,则需要这样做http.StatusOK。 import "net/http" //示例 package main import ("github.com/gin-gonic/gin") func main(){ //创建路由 r:=gin.Default() r.GET("/",func(c *gin.Context){ c.String(http.StatusOK,"hello world") }) } //监听端口 //如果不指定端口则默认为8080 c.run(":80")
基本路由
gin框架中采用的路由库是基于httprouter做的
package main import( "net/http" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.GET("/",func(c *gin.Context){ c.String(http.StatusOK,"hello word") }) r.POST("/delUser",DelUser) //监听80端口 r.run(":8000") }
API参数
可以通过Context的Param方法来获取API参数
package main import( "net/http" "strings" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.GET("/user/:name/*action",func(c *gin.Context){ name:=c.Param("name") action:=c.Param("acion") //截取 action=strings.Trim(action,"/") c.String(http.StatusOK,name+"is"+action) }) //默认监听8080端口 c.Run(":8080") }
URL参数
URL参数可以通过
DefaultQuery()
或Query()
方法获取DefaultQuery()若参数不存在,则返回默认值,Query()若不存在则返回空字符串
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.GET("/user",func(c *gin.Context){ name:= c.DefaultQuery("name","Nice") c.String(http.StatusOK,fmt.Sprintf("%s",name)) }) c.Run(":8000") }
表单参数
表单传输为post请求,http常见的传输格式为四种
- application/json
- application/x-www-form-urlencoded
- application/xml
- multipart/form-data
表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或form-data格式的参数
package main import( "fmt" "net/http" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.POST("form",func(c *gin.Context){ types:=c.DefaultPostForm("type","post") username:=c.PostForm("userName") password:=c.PostForm("pwd") c.String(http.StatusOk,fmt.Sprintf("%v",username) }) c.Run(":8000") }
单个文件
multipart/form-data格式用于文件上传
gin文件上传与原生的net/http方法类似,不同于在gin把原生的request封装到c.Request中
package main import ( "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() //限制上传最大尺寸 r.MaxMultipartMemory=8<<20 r.POST("/upload",func(c *gin.Context){ file,err:=c.FormFile("file") if err!=nil{ c.String(500,"上传出错") c.SaveUploadedFile(file,file.Filename) c.String(http.StatusOK,file.Filename) } }) c.Run(":800") }
上传多个文件
import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) func main() { // 1.创建路由 // 默认使用了2个中间件Logger(), Recovery() r := gin.Default() // 限制表单上传大小 8MB,默认为32MB r.MaxMultipartMemory = 8 << 20 r.POST("/upload", func(c *gin.Context) { form, err := c.MultipartForm() if err != nil { c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error())) } // 获取所有图片 files := form.File["files"] // 遍历所有图片 for _, file := range files { // 逐个存 if err := c.SaveUploadedFile(file, file.Filename); err != nil { c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error())) return } } c.String(200, fmt.Sprintf("upload ok %d files", len(files))) }) //默认端口号是8080 r.Run(":8000") }
routees group
routes group 是为了管理一些相同的URL
package main import ( "github.com/gin-gonic/gin" "net/http" "fmt" ) func main(){ r:=gin.Default() }
路由的拆分与注册
- 基本的路由注册 适用于路由条目较少的简单下面或者项目demo
package main import ( "net/http" "github.com/gin-gonic/gin" ) func helloHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Hello www.topgoer.com!", }) } func main() { r := gin.Default() r.GET("/topgoer", helloHandler) if err := r.Run(); err != nil { fmt.Println("startup service failed, err:%v\n", err) } }
- 路由拆分成单独的文件或包
当项目的规模增大后就不太适合继续在项目的main.go文件中去实现注册的相关逻辑,所以更加偏向于抽出路由模块的代码出来,形成单独一个文件
package router import "github.com/gin-gonic/gin" import ( "net/http" ) func helloHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Hello www.topgoer.com", }) } // SetupRouter 配置路由信息 func SetupRouter() *gin.Engine { r := gin.Default() r.GET("/topgoer", helloHandler) return r } package main import ( "fmt" "router_example/router" ) func main() { r := router.SetupRouter() if err := r.Run(); err != nil { fmt.Println("err failed", err) } }
当前目录结构如下
router_example ├── go.mod ├── main.go └── router └── routers.go
路由拆分成多个文件
当业务规模继续膨胀,单独的一个routers文件或包已经满足不了需求,所以可以分开定义多个路由文件
package router import "github.com/gin-gonic/gin" func LoadSystem(e *gin.Engine) { r := gin.Default() { r.GET("findSystemId", findSystemId) r.GET("findAll",findAll) } } package router import "github.com/gin-gonic/gin" func LoadUser(e *gin.Engine) { r := gin.Default() { r.GET("findByUserId", findByUserId) r.GET("findAllUser", findAllUser) } } main.go func main() { r := gin.Default() //加载系统路由 router.LoadSystem(r) //加载用户路由 router.LoadUser(r) if err := r.Run(); err != nil { fmt.Println(err) } }
当前目录结构如下
router_example ├── go.mod ├── main.go └── router └── user.go └── system.go
路由拆分到不同的APP
项目规模太大,那么更倾向于把业务拆分的更详细一些,例如把不同的业务代码拆分成不同的APP
router_example ├──app | ├──user | | ├──handle.go | | ├──router.go | ├──system | | ├──handle.go | | ├──router.go ├── go.mod ├── main.go └── router └── routers.go
Gin项目目录定义system package system import ( "github.com/gin-gonic/gin" "net/http" ) func findBySystemId(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "findBySystemId", }) } package system import "github.com/gin-gonic/gin" func Routers(e *gin.Engine) { e.GET("findBySystemId", findBySystemId) } user package user import ( "github.com/gin-gonic/gin" "net/http" ) func findByUserId(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "findByUserId", }) } package user import ( "github.com/gin-gonic/gin" ) func Routers(e *gin.Engine) { e.GET("findByUserId", findByUserId) } package main import ( "fmt" "router_example/router" "router_example/service/system" "router_example/service/user" ) func main() { //加载多个路由 router.Include(user.Routers, system.Routers) //初始化 r := router.Init() if err := r.Run(); err != nil { fmt.Println(err) } }
网友评论