Gin框架路由

介紹

  • Gin是一個(gè)golang的微框架,封裝比較優(yōu)雅抖格,API友好,源碼注釋比較明確咕晋,具有快速靈活雹拄,容錯(cuò)方便等特點(diǎn)
  • 對(duì)于golang而言,web框架的依賴要遠(yuǎn)比Python掌呜,Java之類的要小滓玖。自身的net/http足夠簡(jiǎn)單,性能也非常不錯(cuò)
  • 借助框架開發(fā)质蕉,不僅可以省去很多常用的封裝帶來的時(shí)間势篡,也有助于團(tuán)隊(duì)的編碼風(fēng)格和形成規(guī)范

安裝

1.安裝Gin
go get -u github.com/gin-gonic/gin
2.引入包
import "github.com/gin-gonic/gin"
3.(可選)導(dǎo)入net/http。例如模暗,如果使用常量禁悠,則需要這樣做http.StatusOK。
import "net/http"

//示例
package main
import ("github.com/gin-gonic/gin")
func main(){
 //創(chuàng)建路由
 r:=gin.Default()
 r.GET("/",func(c *gin.Context){
     c.String(http.StatusOK,"hello world")
 })
}
//監(jiān)聽端口
//如果不指定端口則默認(rèn)為8080
c.run(":80")

基本路由

gin框架中采用的路由庫(kù)是基于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)
 //監(jiān)聽80端口
 r.run(":8000")
}

API參數(shù)

可以通過Context的Param方法來獲取API參數(shù)

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)
})
//默認(rèn)監(jiān)聽8080端口
c.Run(":8080")
}

URL參數(shù)

URL參數(shù)可以通過DefaultQuery()Query()方法獲取

DefaultQuery()若參數(shù)不存在兑宇,則返回默認(rèn)值碍侦,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")
}

表單參數(shù)

表單傳輸為post請(qǐng)求,http常見的傳輸格式為四種

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

表單參數(shù)可以通過PostForm()方法獲取隶糕,該方法默認(rèn)解析的是x-www-form-urlencoded或form-data格式的參數(shù)

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

單個(gè)文件

  • 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,"上傳出錯(cuò)")
            c.SaveUploadedFile(file,file.Filename)
            c.String(http.StatusOK,file.Filename)
        }
    })
    c.Run(":800")
}

上傳多個(gè)文件

import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
)

func main() {
  // 1.創(chuàng)建路由
  // 默認(rèn)使用了2個(gè)中間件Logger(), Recovery()
  r := gin.Default()
  // 限制表單上傳大小 8MB,默認(rèn)為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 {
          // 逐個(gè)存
          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)))
  })
  //默認(rèn)端口號(hào)是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()
}

路由的拆分與注冊(cè)

  1. 基本的路由注冊(cè) 適用于路由條目較少的簡(jiǎn)單下面或者項(xiàng)目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)
    }
}
  1. 路由拆分成單獨(dú)的文件或包

當(dāng)項(xiàng)目的規(guī)模增大后就不太適合繼續(xù)在項(xiàng)目的main.go文件中去實(shí)現(xiàn)注冊(cè)的相關(guān)邏輯若厚,所以更加偏向于抽出路由模塊的代碼出來拦英,形成單獨(dú)一個(gè)文件

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

當(dāng)前目錄結(jié)構(gòu)如下

router_example
├── go.mod
├── main.go
└── router
    └── routers.go

路由拆分成多個(gè)文件

當(dāng)業(yè)務(wù)規(guī)模繼續(xù)膨脹,單獨(dú)的一個(gè)routers文件或包已經(jīng)滿足不了需求测秸,所以可以分開定義多個(gè)路由文件

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()
  //加載系統(tǒng)路由
  router.LoadSystem(r)
  //加載用戶路由
  router.LoadUser(r)
  if err := r.Run(); err != nil {
      fmt.Println(err)
  }
}

當(dāng)前目錄結(jié)構(gòu)如下

router_example
├── go.mod
├── main.go
└── router
    └── user.go
    └── system.go

路由拆分到不同的APP

項(xiàng)目規(guī)模太大疤估,那么更傾向于把業(yè)務(wù)拆分的更詳細(xì)一些灾常,例如把不同的業(yè)務(wù)代碼拆分成不同的APP

router_example
├──app
|  ├──user
|  |  ├──handle.go
|  |  ├──router.go
|  ├──system
|  |  ├──handle.go
|  |  ├──router.go
├── go.mod
├── main.go
└── router
    └── routers.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() {
  //加載多個(gè)路由
  router.Include(user.Routers, system.Routers)
  //初始化
  r := router.Init()
  if err := r.Run(); err != nil {
      fmt.Println(err)
  }
}




Gin項(xiàng)目目錄定義
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市铃拇,隨后出現(xiàn)的幾起案子钞瀑,更是在濱河造成了極大的恐慌,老刑警劉巖慷荔,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雕什,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡显晶,警方通過查閱死者的電腦和手機(jī)贷岸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磷雇,“玉大人偿警,你說我怎么就攤上這事∥希” “怎么了螟蒸?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)崩掘。 經(jīng)常有香客問我七嫌,道長(zhǎng),這世上最難降的妖魔是什么苞慢? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任抄瑟,我火速辦了婚禮,結(jié)果婚禮上枉疼,老公的妹妹穿的比我還像新娘皮假。我一直安慰自己,他們只是感情好骂维,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布惹资。 她就那樣靜靜地躺著,像睡著了一般航闺。 火紅的嫁衣襯著肌膚如雪褪测。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天潦刃,我揣著相機(jī)與錄音侮措,去河邊找鬼。 笑死乖杠,一個(gè)胖子當(dāng)著我的面吹牛分扎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胧洒,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼畏吓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼墨状!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起菲饼,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤肾砂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后宏悦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镐确,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年饼煞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了源葫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡派哲,死狀恐怖臼氨,靈堂內(nèi)的尸體忽然破棺而出掺喻,到底是詐尸還是另有隱情芭届,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布感耙,位于F島的核電站褂乍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏即硼。R本人自食惡果不足惜逃片,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望只酥。 院中可真熱鬧褥实,春花似錦、人聲如沸裂允。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)绝编。三九已至僻澎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間十饥,已是汗流浹背窟勃。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逗堵,地道東北人秉氧。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蜒秤,于是被迫代替她去往敵國(guó)和親谬运。 傳聞我的和親對(duì)象是個(gè)殘疾皇子隙赁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容