介绍

  • Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点
  • 对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错
  • 借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范

安装

```go 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”)

  1. <a name="29667296"></a>
  2. #### 基本路由
  3. > gin框架中采用的路由库是基于httprouter做的
  4. > ```go
  5. package main
  6. import(
  7. "net/http"
  8. "github.com/gin-gonic/gin"
  9. )
  10. func main(){
  11. r:=gin.Default()
  12. r.GET("/",func(c *gin.Context){
  13. c.String(http.StatusOK,"hello word")
  14. })
  15. r.POST("/delUser",DelUser)
  16. //监听80端口
  17. r.run(":8000")
  18. }

API参数

可以通过Context的Param方法来获取API参数

  1. package main
  2. import(
  3. "net/http"
  4. "strings"
  5. "github.com/gin-gonic/gin"
  6. )
  7. func main(){
  8. r:=gin.Default()
  9. r.GET("/user/:name/*action",func(c *gin.Context){
  10. name:=c.Param("name")
  11. action:=c.Param("acion")
  12. //截取
  13. action=strings.Trim(action,"/")
  14. c.String(http.StatusOK,name+"is"+action)
  15. })
  16. //默认监听8080端口
  17. c.Run(":8080")
  18. }

URL参数

URL参数可以通过DefaultQuery()Query()方法获取

DefaultQuery()若参数不存在,则返回默认值,Query()若不存在则返回空字符串

  1. package main
  2. import (
  3. "net/http"
  4. "github.com/gin-gonic/gin"
  5. )
  6. func main(){
  7. r:=gin.Default()
  8. r.GET("/user",func(c *gin.Context){
  9. name:= c.DefaultQuery("name","Nice")
  10. c.String(http.StatusOK,fmt.Sprintf("%s",name))
  11. })
  12. c.Run(":8000")
  13. }

表单参数

表单传输为post请求,http常见的传输格式为四种

  • application/json
  • application/x-www-form-urlencoded
  • application/xml
  • multipart/form-data

表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或form-data格式的参数

  1. package main
  2. import(
  3. "fmt"
  4. "net/http"
  5. "github.com/gin-gonic/gin"
  6. )
  7. func main(){
  8. r:=gin.Default()
  9. r.POST("form",func(c *gin.Context){
  10. types:=c.DefaultPostForm("type","post")
  11. username:=c.PostForm("userName")
  12. password:=c.PostForm("pwd")
  13. c.String(http.StatusOk,fmt.Sprintf("%v",username)
  14. })
  15. c.Run(":8000")
  16. }

单个文件

  • multipart/form-data格式用于文件上传

  • gin文件上传与原生的net/http方法类似,不同于在gin把原生的request封装到c.Request中

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. )
  5. func main(){
  6. r:=gin.Default()
  7. //限制上传最大尺寸
  8. r.MaxMultipartMemory=8<<20
  9. r.POST("/upload",func(c *gin.Context){
  10. file,err:=c.FormFile("file")
  11. if err!=nil{
  12. c.String(500,"上传出错")
  13. c.SaveUploadedFile(file,file.Filename)
  14. c.String(http.StatusOK,file.Filename)
  15. }
  16. })
  17. c.Run(":800")
  18. }

上传多个文件

```go 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”) }

  1. <a name="84bf9a07"></a>
  2. #### routees group
  3. > routes group 是为了管理一些相同的URL
  4. > ```go
  5. package main
  6. import (
  7. "github.com/gin-gonic/gin"
  8. "net/http"
  9. "fmt"
  10. )
  11. func main(){
  12. r:=gin.Default()
  13. }

路由的拆分与注册

  1. 基本的路由注册 适用于路由条目较少的简单下面或者项目demo

```go package main

import ( “net/http”

  1. "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) } }

  1. > 2. 路由拆分成单独的文件或包
  2. > 当项目的规模增大后就不太适合继续在项目的main.go文件中去实现注册的相关逻辑,所以更加偏向于抽出路由模块的代码出来,形成单独一个文件
  3. > ```go
  4. package router
  5. import "github.com/gin-gonic/gin"
  6. import (
  7. "net/http"
  8. )
  9. func helloHandler(c *gin.Context) {
  10. c.JSON(http.StatusOK, gin.H{
  11. "message": "Hello www.topgoer.com",
  12. })
  13. }
  14. // SetupRouter 配置路由信息
  15. func SetupRouter() *gin.Engine {
  16. r := gin.Default()
  17. r.GET("/topgoer", helloHandler)
  18. return r
  19. }
  20. package main
  21. import (
  22. "fmt"
  23. "router_example/router"
  24. )
  25. func main() {
  26. r := router.SetupRouter()
  27. if err := r.Run(); err != nil {
  28. fmt.Println("err failed", err)
  29. }
  30. }

当前目录结构如下

  1. router_example
  2. ├── go.mod
  3. ├── main.go
  4. └── router
  5. └── routers.go

路由拆分成多个文件

当业务规模继续膨胀,单独的一个routers文件或包已经满足不了需求,所以可以分开定义多个路由文件

```go 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) } }

  1. > 当前目录结构如下
  2. > ```go
  3. router_example
  4. ├── go.mod
  5. ├── main.go
  6. └── router
  7. └── user.go
  8. └── system.go

路由拆分到不同的APP

项目规模太大,那么更倾向于把业务拆分的更详细一些,例如把不同的业务代码拆分成不同的APP

  1. router_example
  2. ├──app
  3. | ├──user
  4. | | ├──handle.go
  5. | | ├──router.go
  6. | ├──system
  7. | | ├──handle.go
  8. | | ├──router.go
  9. ├── go.mod
  10. ├── main.go
  11. └── router
  12. └── routers.go

```go 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) } } ```

Gin框架路由 - 图1