Gin框架使用
*基于httprouter开发的web框架
*提供Martini风格的API,但比Martini要快40倍
*非常轻量级,使用起来非常简洁
Gin框架安装与使用
*安装:go get -u github.com/gin-gonic/gin
*import"github.com/gin-gonic/gin"
第一个Gin程序
package main
import "github.com/gin-gonic/gin"
func main(){
r := gin.Default()//创建一个默认的路由引擎
r.GET("/ping",func(c *gin.Context){//创建测试的路由
//GET:请求方式 /ping:请求的路径
//当客户端以GET方法请求/ping路径时,会执行后面的匿名函数
//c.JSON:返回JSON格式的数据
c.JSON(200,gin.H{
"message":"pong",
})
})
//启动HTTP服务,默认在0.0.0.0:8200启动服务
r.Run(":8200")
}
1.首先,我们使用了gin.Default()生成了一个实例,这个实例即WSGI应用程序(Web服务器网关接口)。
2.接下来,我们使用了r.GET("/",…)声明了一个路由,告诉Gin什么样的URL(在www上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL)能触发传入的函数,这个函数返回我们想要显示在用户浏览器中的信息。
3.最后用r.Run()函数来让应用运行在本地服务器上,默认监听端口是8200,可以传入参数设置端口,例如r.Run(":9999")即运行在9999端口。
4.然后使用浏览器打开127.0.0.1:8200/ping
就能看到一串JSON字符串
请求路由-多种请求
package main
import "github.com/gin-gonic/gin"
func main(){
r := gin.Default()
r.GET("/get",func(c *gin.Context){
c.String(200,"get")
})
r.POST("/post",func(c *gin.Context){
c.String(200,"post")
})
r.Handle("DELETE","/delete",
func(c *gin.Context){
c.String(200,"delete")
})
r.Any("/any",func(c *gin.Context){
c.String(200,"any")
})
r.Run()
}
请求路由-静态文件夹
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main(){
r := gin.Default()
r.Static("/assets","./assets")
//先设置路由,再设置相对文件夹
//另外一种写法
r.StaticFS("/static",http.Dir("static"))
//先设置路由,再设置资源
//设置单个静态文件
r.StaticFile("/favicon.ico",
"./favicon.ico")
//设置路由,设置资源
r.Run()//启动服务器
}
请求路由-参数作为url
package main
import "github.com/gin-gonic/gin"
func main(){
r := gin.Default()
r.GET("/:name/:id",func(c *gin.Context){
c.JSON(200,gin.H{
"name":c.Param("name"),
"id":c.Param("id"),
})
})
r.Run()
}
请求路由-泛绑定
package main
import "github.com/gin-gonic/gin"
func main(){
r := gin.Default()
r.GET("/user/*action",
func(c *gin.Context){
c.String(200,"hello world")
})
r.Run()
}
获取请求参数-获取GET参数
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main(){
r := gin.Default()
r.GET("/test",func(c *gin.Context){
firstName := c.Query("first_name")
lastName := c.DefaultQuery("last_name",
"last_default_name")
c.String(http.StatusOK,"%s,%s",
firstName,lastName)
})
r.Run(":8080")
}
获取请求参数-获取body内容
package main
import (
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
)
func main(){
r := gin.Default()
r.POST("/test",func(c *gin.Context){
bodyByts,err := ioutil.ReadAll(c.Request.Body)
if err != nil{
c.String(http.StatusBadRequest,err.Error())
c.Abort()
}
c.String(http.StatusOK,string(bodyByts))
})
r.Run()
}
获取请求参数-获取bind参数
package main
import (
"github.com/gin-gonic/gin"
"time"
)
type Person struct{
Name string `form:"name"`
Address string `form:"address"`
Birthday time.Time `form:"birthday"`
}
func main(){
r := gin.Default()
r.GET("/testing",testing)
r.POST("/testing",testing)
r.Run()
}
func testing(c *gin.Context){
var person Person
if err := c.ShouldBind(&person);err==nil{
c.String(200,"%v",person)
}else{
c.String(200,"person bind error:%v",err)
}
}
验证请求参数-结构体验证
package main
import "github.com/gin-gonic/gin"
type Person struct{
Age int `form:"age" binding:"required,gt=10"`
Name string `form:"name" binding:"required"`
Address string `form:"address" binding:"required"`
}
func main(){
r := gin.Default()
r.GET("/testing",func(c *gin.Context){
var person Person
if err := c.ShouldBind(&person);err != nil{
c.String(500,"%v",err)
}
c.String(200,"%v",person)
})
r.Run()
}
验证请求参数-自定义验证规则
package main
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"net/http"
"time"
)
type Booking struct{
CheckIn time.Time `form:"check_in" validate:"required,bookableDate" time_format:"2006-01-02"`
CheckOut time.Time `form:"check_out" validate:"required,gtfield=CheckIn" time_format:"2006-01-02`
}
func main(){
r := gin.Default()
validate := validator.New()
validate.RegisterValidation("bookableDate",bookableDate)
r.GET("/bookable",func(c *gin.Context){
var book Booking
if err := c.ShouldBind(&book);err != nil{
c.JSON(http.StatusInterServerError,gin.H{
"error":err.Error(),
})
c.Abort()
return
}
if err := validate.Struct(book);err != nil{
c.JSON(http.StatusInternalServerError,gin.H{
"error":err.Error(),
})
c.Abort()
return
}
c.JSON(http.StatusOK,gin.H{
"message":"OK",
"booking":book,
})
})
r.Run()
}
func bookableDate(fl validator.FieldLevel)bool{
if date,ok := fl.Field().Interface().(time.Time);ok{
today := time.Now()
if date.Unix() > today.Unix(){
return true
}
}
return false
}
验证请求参数-多语言翻译验证
package main
import (
"github.com/gin-gonic/gin"
en2 "github.com/go-playground/locales/en"
zh2 "github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "gopkg.in/go-playground/validator.v9/translations/en"
zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"
)
type people struct{
Age int `form:"age" validate:"required,gt=10"`
Name string `form:"name" validate:"required"`
Address string `form:"address" validate:"required"`
}
var(
Uni *ut.UniversalTranslator
Validate *validator.Validate
)
//验证信息多语言化
func main(){
Validate = validator.New()//创建一个验证器
zh := zh2.New()
en := en2.New()
Uni = ut.New(zh,en)//创建翻译器,翻译器里有可支持的语言
r := gin.Default()
r.GET("/testing",func(c *gin.Context){
locale := c.DefaultQuery("locale",
"zh")
trans,_ := Uni.GetTranslator("locale")
switch locale{
case "zh":
zh_translations.RegisterDefaultTranslations(Validate,trans)
case "en":
en_translations.RegisterDefaultTranslations(Validate,trans)
default:
zh_translations.RegisterDefaultTranslations(Validate,trans)
}
var person people
if err := c.ShouldBind(&person);err != nil{//结构绑定
c.String(500,"%v",err)
c.Abort()
return
}
if err := Validate.Struct(person);err != nil{
errs := err.(validator.ValidationErrors)
sliceErrs := []string{}
for _,e := range errs{
sliceErrs=append(sliceErrs,e.Translate(trans))
}
c.String(500,"%v",sliceErrs)
c.Abort()
return
}
c.String(200,"%v",person)
})
r.Run()
}
Gin中间件
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等
中间件-使用
package main
import "github.com/gin-gonic/gin"
func main(){
r := gin.New()//这次用new来实现
r.Use(gin.Logger())//设置中间件
r.GET("/test",func(c *gin.Context){
name := c.DefaultQuery("name","default_name")
c.String(200,"%s",name)
})
r.Run()
}
那么,想把错误打印到文件应该怎么办呢?、
package main
import (
"github.com/gin-gonic/gin"
"io"
"os"
)
func main(){
f,_ := os.Create("gin.log")
gin.DefaultWriter = io.MultiWriter(f)
gin.DefaultErrorWriter = io.MultiWriter(f)
r := gin.New()//这次用new来实现
r.Use(gin.Logger())//设置中间件
r.GET("/test",func(c *gin.Context){
name := c.DefaultQuery("name","default_name")
c.String(200,"%s",name)
})
r.Run()
}
gin.Recovery的作用
package main
import (
"github.com/gin-gonic/gin"
"io"
"os"
)
func main(){
f,_ := os.Create("gin.log")
gin.DefaultWriter = io.MultiWriter(f)
gin.DefaultErrorWriter = io.MultiWriter(f)
r := gin.New()//这次用new来实现
r.Use(gin.Logger(),gin.Recovery())//设置中间件
r.GET("/test",func(c *gin.Context){
name := c.DefaultQuery("name","default_name")
panic("test panic")//加上这个程序不至于报错
c.String(200,"%s",name)
})
r.Run()
}
中间件-自定义中间件