Gin Web框架
簡介
- 基於httprouter開發的web框架:https://github.com/gin-gonic/gin
- 提供Martini風格的API,但比Martini要快40倍
- 非常輕量級,使用簡潔
Gin框架的安裝與使用
- 安裝: go get -u github.com/gin-gonic/gin
基本使用
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run("0.0.0.0:9090")
}
支持restful風格的API
- 把設計的API抽象成一個個資源,用URI來標識
- 針對每一個資源,使用統一的方法進行操作
- 統一的方法: GET,POST,PUT,DELETE
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Result struct {
Message string `json:"message"`
Code int `json:"code"`
}
func handleUserInfo(c *gin.Context) {
var result Result = Result{
Message: "hello",
Code: 0,
}
c.JSON(http.StatusOK,result)
}
func main() {
r := gin.Default()
r.GET("/user/info", handleUserInfo)
r.Run("0.0.0.0:9090")
}
queryString設計
- 查詢類:http://127.0.0.1:9090/user/info?username=dadasd&&passwd=1234
- 路由類:http://127.0.0.1:9090/user/info/2020/12
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Result struct {
Message string `json:"message"`
Code int `json:"code"`
}
type UserInfo struct {
Result
UserName string `json:"username"`
Passwd string `json:"passwd"`
}
func handleUserParams(c *gin.Context) {
//查詢類接口
username := c.Query("username")
passwd := c.DefaultQuery("passwd","adcdefg")
var result UserInfo = UserInfo{
Result{
Message: "success",
Code: 200,
},
username,
passwd,
}
c.JSON(http.StatusOK,result)
}
func handleUserInfo(c *gin.Context) {
//路由類接口
username := c.Param("username")
passwd := c.Param("passwd")
var result UserInfo = UserInfo{
Result{
Message: "success",
Code: 200,
},
username,
passwd,
}
c.JSON(http.StatusOK,result)
}
func main() {
r := gin.Default()
r.GET("/user/info", handleUserParams)
r.GET("/user/info/:username/:passwd", handleUserInfo)
r.Run("0.0.0.0:9090")
}
Gin框架參數傳遞
獲取表單參數
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Result struct {
Message string `json:"message"`
Code int `json:"code"`
}
type UserInfo struct {
Result
UserName string `json:"username"`
Passwd string `json:"passwd"`
}
func handleUserInfo(c *gin.Context) {
username := c.PostForm("username")
passwd := c.PostForm("passwd")
var result UserInfo = UserInfo{
Result: Result{
Message: "success",
Code: 200,
},
UserName: username,
Passwd: passwd,
}
c.JSON(http.StatusOK,result)
}
func main() {
r := gin.Default()
r.POST("/user/info",handleUserInfo)
r.Run(":9090")
}
單文件上傳
func handleUpload(c *gin.Context) {
file,err := c.FormFile("testfile")
if err != nil {
fmt.Printf("upload file faild,err:%v\n",err)
return
}
//文件上傳路徑
filename := fmt.Sprintf("/Users/wanghui/go/src/oldBoy/day8/tmp/%s",file.Filename)
//文件保存
err = c.SaveUploadedFile(file,filename)
if err != nil {
fmt.Printf("save file faild,err:%v\n",err)
return
}
//狀態返回
c.JSON(http.StatusOK,"file upload success")
}
func main() {
r := gin.Default()
r.POST("/file/upload",handleUpload)
r.Run(":9090")
}
多文件上傳
func multiHandleUpload(c *gin.Context) {
//多文件上傳
form,err := c.MultipartForm()
if err != nil {
fmt.Printf("upload file faild,err:%v\n",err)
return
}
files := form.File["testfile"]
for _,file := range files {
filename := fmt.Sprintf("/Users/wanghui/go/src/oldBoy/day8/tmp/%s",file.Filename)
err = c.SaveUploadedFile(file,filename)
if err != nil {
fmt.Printf("save file faild,err:%v\n",err)
return
}
}
//狀態返回
c.JSON(http.StatusOK,"file upload success")
}
func main() {
r := gin.Default()
r.POST("/file/upload",handleUpload)
r.POST("/files",multiHandleUpload)
r.Run(":9090")
}
通過postman上傳文件
路由分組
func main() {
r := gin.Default()
v1Group := r.Group("/v1")
v1Group.POST("/user/info",handleUserInfo)
v1Group.POST("/user/info2",handleUserInfo)
r.Run(":9090")
}
gin的參數綁定
- 爲什麼要使用參數綁定
- 通過反射的機制,自動提取querystring、form表單,json,xml等參數到struct中
- 通過http協議中的content type,識別是json,xml或者表單
type UserInfo struct {
UserName string `form:"username" json:"username" binding:"required"`
Passwd string `form:"passwd" json:"passwd" binding:"required"`
Age int `form:"age" json:"age" binding:"required"`
Sex string `form:"sex" json:"sex" binding:"required"`
}
func PostUserInfo(c *gin.Context) {
var UserInfo UserInfo
//表單綁定,使用指針
err := c.ShouldBind(&UserInfo)
if err != nil {
return
}
c.JSON(http.StatusOK,UserInfo)
}
func PostUserInfoJson(c *gin.Context) {
var UserInfo UserInfo
//表單綁定,使用指針
err := c.ShouldBindJSON(&UserInfo)
if err != nil {
return
}
c.JSON(http.StatusOK,UserInfo)
}
func GetUserInfoJson(c *gin.Context) {
var UserInfo UserInfo
//表單綁定,使用指針
err := c.ShouldBindJSON(&UserInfo)
if err != nil {
return
}
c.JSON(http.StatusOK,UserInfo)
}
func main() {
r := gin.Default()
v1Group := r.Group("/v1")
v1Group.POST("/user/infos",PostUserInfo)
v1Group.POST("/user/infojson",PostUserInfoJson)
v1Group.GET("/user/info",GetUserInfoJson)
r.Run(":9090")
}
渲染
- gin.Context.JSON方法進行渲染
type UserInfo struct {
UserName string `form:"username" json:"username" binding:"required"`
Passwd string `form:"passwd" json:"passwd" binding:"required"`
}
func GetUserInfoJson(c *gin.Context) {
var userInfo = &UserInfo{
UserName: "zhansan",
Passwd: "aaaa",
}
c.XML(200,userInfo)
}
func main() {
r := gin.Default()
v1Group := r.Group("/v1")
v1Group.GET("/user/info",GetUserInfoJson)
r.Run(":9090")
}
HTML模板渲染
- templates/post.html
{{ define "index.tmpl" }}
<html><h1>
{{ . }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}
- server.go
func HandleHtmml(c *gin.Context) {
c.HTML(200,"index.tmpl","mmmmmmmm")
}
func main() {
r := gin.Default()
r.LoadHTMLGlob("./templates/*")
r.GET("/user/info",HandleHtmml)
r.Run(":9090")
}
gin中間件
- gin框架在請求處理過程中,加入用戶自己的鉤子函數,這個鉤子函數就叫做中間件
- 因此,可以使用中間件處理一些公共業務邏輯,比如耗時統計,日誌打印,登錄校驗等
func StatCost(c *gin.Context) {
//中間件
start := time.Now()
fmt.Printf("start \n")
c.Next()
lattacy := time.Since(start)
fmt.Printf("cost Time is %dms\n", lattacy/1000/1000)
}
func funcHello(c *gin.Context) {
fmt.Printf("request start\n")
time.Sleep(time.Second * 3)
c.JSON(http.StatusOK, "hello world")
}
func main() {
r := gin.Default()
r.Use(StatCost)
r.GET("/hello", funcHello)
r.Run(":9090")
}
gin框架路由原理
- 路由部分使用的是:https://github.com/julienschmidt/httprouter
- 對於路由的規則,httprouter會構造一顆前綴樹