Gin框架介绍
- 基于httprouter开发的web框架。http://github.com/julienschmidt/httprouter
- 提供Martini风格的API,但比Martini要快40倍
- 非常轻量级,使用起来非常简洁
Gin框架安装与使用
- 安装: go get -u github.com/gin-gonic/gin
- import "github.com/gin-gonic/gin"
package main
import "github.com/gin-gonic/gin"
func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run(":9090") // 默认:listen and serve on 0.0.0.0:8080
}
支持restful风格的API
func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
})
})
r.POST("/ping", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
参数传递
- 通过querystring传递, 比如: /user/search?username=少林&address=北京
func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/user/search", func(c *gin.Context) {
//username := c.DefaultQuery("username", "少林")
username = c.Query("username")
address := c.Query("address")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"username": username,
"address": address,
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
- 通过路径传递, 比如: /user/search/少林/北京
func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/user/info", func(c *gin.Context) {
//这种方式是,如果没传递则使用参数二当默认值
//username := c.DefaultQuery("username", "少林")
username = c.Query("username")
address := c.Query("address")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"username": username,
"address": address,
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
- 获取表单提交
func testPostForm(c *gin.Context) {
name := c.PostForm("name") //获取表单提交的数据
c.JSON(200, gin.H{
"message": "test",
name: name,
})
}
- 单个文件上传
func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// single file
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
})
return
}
log.Println(file.Filename)
dst := fmt.Sprintf("C:/tmp/%s", file.Filename)
// Upload the file to specific dst.
c.SaveUploadedFile(file, dst)
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
})
})
router.Run(":8080")
}
- 多文件上传
func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["file"]
for index, file := range files {
log.Println(file.Filename)
dst := fmt.Sprintf("C:/tmp/%s_%d", file.Filename, index)
c.SaveUploadedFile(file, dst)
}
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("%d files uploaded!", len(files)),
})
})
router.Run(":8080")
}
路由分组
func login(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
}
func submit(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
}
func main() {
//Default返回一个默认的路由引擎
router := gin.Default()
// Simple group: v1
v1 := router.Group("/v1")
{
v1.POST("/login", login)
v1.POST("/submit", submit)
}
// Simple group: v2
v2 := router.Group("/v2")
{
v2.POST("/login", login)
v2.POST("/submit", submit)
}
router.Run(":8080")
}
简单案例
package main
import "github.com/gin-gonic/gin"
func pingHandle(c *gin.Context) {
// c.DefaultQuery("name")
name := c.Query("name")
c.JSON(200, gin.H{
"message": "pong",
name: name,
})
}
func testHandle(c *gin.Context) {
name := c.Param("name")
c.JSON(200, gin.H{
"message": "test",
name: name,
})
}
func testPostForm(c *gin.Context) {
name := c.PostForm("name") //获取表单提交的数据
c.JSON(200, gin.H{
"message": "test",
name: name,
})
}
//文件可能很大,gin默认内存最大文件是32M,超出部分则流形式一点点读,也可以设置
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
func main() {
r := gin.Default()
r.GET("ping", pingHandle)
r.GET("/test/:name/:age", testHandle)
r.GET("/test/form", testHandle)
r.Run(":9090") //默认不传递则是9090
}
Gin框架参数绑定
- 为什么要参数绑定,本质上是方便,提高开发效率
- 通过反射的机制,自动提取querystring、form表单、json、xml等参数到struct中
- 通过http协议中的context type,识别是json、xml或者表单
- 该种方式很全能,可以识别各种传参,而且使用简单,推荐
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// Binding from JSON
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
router := gin.Default()
// Example for binding JSON ({"user": "manu", "password": "123"})
router.POST("/loginJSON", func(c *gin.Context) {
var login Login
if err := c.ShouldBindJSON(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// Example for binding a HTML form (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) {
var login Login
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// Example for binding a HTML querystring (user=manu&password=123)
router.GET("/loginForm", func(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
router.Run(":8080")
}
Gin框架渲染
- 渲染json
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// gin.H is a shortcut for map[string]interface{}
r.GET("/someJSON", func(c *gin.Context) {
//第一种方式,自己拼json
c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
r.GET("/moreJSON", func(c *gin.Context) {
//第二种方式,自动序列化
// You also can use a struct
var msg struct {
Name string `json:"user"`
Message string
Number int
}
msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
// 此处会自动序列化结构体然后传输
c.JSON(http.StatusOK, msg)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
- 渲染xml
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/moreXML", func(c *gin.Context) {
// You also can use a struct
type MessageRecord struct {
Name string
Message string
Number int
}
var msg MessageRecord
msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
c.XML(http.StatusOK, msg)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
- 渲染模板
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
})
router.GET("/users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
})
})
router.Run(":8080")
}
Gin框架中间件
- Gin框架允许在请求处理过程中,加入用户自己的钩子函数。这个钩子函数就叫中间件
- 因此,可以使用中间件处理一些公共业务逻辑,比如耗时统计,日志打印,登陆校验.
编写自己的中间件
- Use方式使用
- 中间件函数只要返回值是参数是c *gin.Context即可
- 中间件使用可以使用gin.New()或gin.Default(),default默认包含两个中间件,错误输出中间件,请求时间中间件
func StatCost() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
//可以设置一些公共参数
c.Set("example", "12345")
//等其他中间件先执行
c.Next()
//获取耗时
latency := time.Since(t)
log.Print(latency)
}
}
func main() {
//r := gin.New()
r := gin.Default()
r.Use(StatCost())
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
// it would print: "12345"
log.Println(example)
c.JSON(http.StatusOK, gin.H{
"message": "success",
})
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
Gin框架路由原理
- 路由部分用的是:http://github.com/julienschmidt/httprouter
- 对于所有的路由规则,httprouter会构造一颗
前缀树
1.jpg - Gin框架路由介绍
package main
import "github.com/gin-gonic/gin"
func index(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "index",
})
}
func main() {
//Default返回一个默认的路由引擎
router := gin.Default()
router.POST("/", index)
router.POST("/search", index)
router.POST("/support", index)
router.POST("/blog/:post", index)
router.POST("/about", index)
router.POST("/contact", index)
router.Run(":8080")
}
-
生成的前缀树,如下所示
2.jpg
网友评论