zoukankan      html  css  js  c++  java
  • Gin框架使用详解

    1.什么是Gin
    Gin是go编写的一个web应用框架。

    2.Gin安装

    go get github.com/gin-gonic/gin
    

    3.Gin使用示例

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func main() {
    	// 初始化引擎
    	engine := gin.Default()
    	// 注册一个路由和处理函数
    	engine.Any("/", WebRoot)
    	// 绑定端口,然后启动应用
    	engine.Run(":9205")
    }
    
    /**
    * 根请求处理函数
    * 所有本次请求相关的方法都在 context 中,完美
    * 输出响应 hello, world
    */
    func WebRoot(context *gin.Context) {
    	context.String(http.StatusOK, "hello, world")
    }
    

    运行结果:

    4.路由(Router)
    1)restful api
    注册路由方法有GET,POST,PUT,PATCH,DELETE,OPTIONS

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	router.GET("/someGet", getting)
    	router.POST("/somePost", posting)
    	router.PUT("/somePut", putting)
    	router.DELETE("/someDelete", deleting)
    	router.PATCH("/somePatch", patching)
    	router.HEAD("/someHead", head)
    	router.OPTIONS("/someOptions", options)
    
    	// 默认绑定 :8080
    	router.Run()
    }
    

    2)动态路由(参数路由)
    如/user/:id

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	// 注册一个动态路由
      	// 可以匹配 /user/joy
      	// 不能匹配 /user 和 /user/
    	router.GET("/user/:name", func(c *gin.Context) {
    		// 使用 c.Param(key) 获取 url 参数
    		name := c.Param("name")
    		c.String(http.StatusOK, "Hello %s", name)
    	})
    
      	// 注册一个高级的动态路由
    	// 该路由会匹配 /user/john/ 和 /user/john/send
    	// 如果没有任何路由匹配到 /user/john, 那么他就会重定向到 /user/john/,从而被该方法匹配到
    	router.GET("/user/:name/*action", func(c *gin.Context) {
    		name := c.Param("name")
    		action := c.Param("action")
    		message := name + " is " + action
    		c.String(http.StatusOK, message)
    	})
    
    	router.Run(":8080")
    }
    
    // 省略的代码 ...
    

    3)路由组
    url统一前缀

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	// 定义一个组前缀
      	// /v1/login 就会匹配到这个组
    	v1 := router.Group("/v1")
    	{
    		v1.POST("/login", loginEndpoint)
    		v1.POST("/submit", submitEndpoint)
    		v1.POST("/read", readEndpoint)
    	}
    
    	// 定义一个组前缀
      	// 不用花括号包起来也是可以的。上面那种只是看起来会统一一点。看你个人喜好
    	v2 := router.Group("/v2")
    	v2.POST("/login", loginEndpoint)
    	v2.POST("/submit", submitEndpoint)
    	v2.POST("/read", readEndpoint)
    
    	router.Run(":8080")
    }
    
    // 省略的代码 ...
    

    5.中间件(middleware)
    如验证Auth,身份鉴别,集中处理返回的数据等等。
    1)单个路由中间件

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	// 注册一个路由,使用了 middleware1,middleware2 两个中间件
    	router.GET("/someGet", middleware1, middleware2, handler)
      
    	// 默认绑定 :8080
    	router.Run()
    }
    
    func handler(c *gin.Context) {
    	log.Println("exec handler")
    }
    
    func middleware1(c *gin.Context) {
    	log.Println("exec middleware1")
      
    	//你可以写一些逻辑代码
      
    	// 执行该中间件之后的逻辑
    	c.Next()
    }
    
    // 省略的代码 ...
    

    c.Next()控制调用逻辑

    2)路由组使用中间件
    中间件放到路由组Group中

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	// 定义一个组前缀, 并使用 middleware1 中间件
      	// 访问 /v2/login 就会执行 middleware1 函数
    	v2 := router.Group("/v2", middleware1)
    	v2.POST("/login", loginEndpoint)
    	v2.POST("/submit", submitEndpoint)
    	v2.POST("/read", readEndpoint)
    
    	router.Run(":8080")
    }
    
    // 省略的代码 ...
    

    6.参数
    1)Url查询参数
    使用c.Query方法,该方法始终返回一个string类型的数据。

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	// 注册路由和Handler
    	// url为 /welcome?firstname=Jane&lastname=Doe
    	router.GET("/welcome", func(c *gin.Context) {
    		// 获取参数内容
    		// 获取的所有参数内容的类型都是 string
    		// 如果不存在,使用第二个当做默认内容
    		firstname := c.DefaultQuery("firstname", "Guest")
    		// 获取参数内容,没有则返回空字符串
    		lastname := c.Query("lastname") 
    
    		c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
    	})
    	router.Run(":8080")
    }
    

    2)表单和body参数(Multipart/Urlencoded Form)
    对于POST请求,无论是multipart/form-data,还是application/x-www-form-urlencoded格式,都可以使用c.PostForm获取到参数,该方法始终返回一个string类型的数据

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	router.POST("/form_post", func(c *gin.Context) {
    		// 获取post过来的message内容
    		// 获取的所有参数内容的类型都是 string
    		message := c.PostForm("message")
    		// 如果不存在,使用第二个当做默认内容
    		nick := c.DefaultPostForm("nick", "anonymous")
    
    		c.JSON(200, gin.H{
    			"status":  "posted",
    			"message": message,
    			"nick":    nick,
    		})
    	})
    	router.Run(":8080")
    }
    

    3)上传文件
    使用c.FormFile获取文件

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    	// 设置文件上传大小 router.MaxMultipartMemory = 8 << 20  // 8 MiB
    	// 处理单一的文件上传
    	router.POST("/upload", func(c *gin.Context) {
    		// 拿到这个文件
    		file, _ := c.FormFile("file")
    		log.Println(file.Filename)
    		c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
    	})
      
    	// 处理多个文件的上传
    	router.POST("/uploads", func(c *gin.Context) {
    		form, _ := c.MultipartForm()
    		// 拿到集合
    		files := form.File["upload[]"]
    		for _, file := range files {
    			log.Println(file.Filename)
    		}
    		c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
    	})
    	router.Run(":8080")
    }
    

    使用curl工具测试一下:

    # 单一文件上传
    $ curl -X POST http://localhost:8080/upload 
      -F "file=@/Users/appleboy/test.zip" 
      -H "Content-Type: multipart/form-data"
    
    # 多文件上传
    $ curl -X POST http://localhost:8080/uploads 
      -F "upload[]=@/Users/appleboy/test1.zip" 
      -F "upload[]=@/Users/appleboy/test2.zip" 
      -H "Content-Type: multipart/form-data"
    

    4)JSON参数(application/json)
    使用c.GetRawData

    // 省略的代码 ...
    
    func main() {
    	router := gin.Default()
    
    	router.POST("/post", func(c *gin.Context) {
    		// 获取原始字节
    		d, err := c.GetRawData()
    		if err!=nil {
    			log.Fatalln(err)
    		}
    		log.Println(string(d))
    		c.String(200, "ok")
    	})
    	router.Run(":8080")
    }
    

    curl请求示例:

    $ curl -v -X POST 
      http://localhost:8080/post 
      -H 'content-type: application/json' 
      -d '{ "user": "manu" }'
    

    7.数据绑定
    将用户传来的参数自动跟我们定义的结构体绑定在一起
    1)绑定Url查询参数
    使用c.ShouldBindQuery方法

    package main
    
    import (
    	"log"
    	"github.com/gin-gonic/gin"
    )
    
    // 定义一个 Person 结构体,用来绑定 url query
    type Person struct {
    	Name    string `form:"name"` // 使用成员变量标签定义对应的参数名
    	Address string `form:"address"`
    }
    
    func main() {
    	route := gin.Default()
    	route.Any("/testing", startPage)
    	route.Run(":8085")
    }
    
    func startPage(c *gin.Context) {
    	var person Person
    	// 将 url 查询参数和person绑定在一起
    	if c.ShouldBindQuery(&person) == nil {
    		log.Println("====== Only Bind By Query String ======")
    		log.Println(person.Name)
    		log.Println(person.Address)
    	}
    	c.String(200, "Success")
    }
    

    2)绑定url查询参数和POST参数
    使用c.ShouldBind方法,该方法会检查url查询参数和POST参数,并且会根据content-type类型,优先匹配JSON或XML,之后才是Form

    package main
    
    import "log"
    import "github.com/gin-gonic/gin"
    import "time"
    
    // 定义一个 Person 结构体,用来绑定数据
    type Person struct {
    	Name     string    `form:"name"`
    	Address  string    `form:"address"`
    	Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
    }
    
    func main() {
    	route := gin.Default()
    	route.GET("/testing", startPage)
    	route.Run(":8085")
    }
    
    func startPage(c *gin.Context) {
    	var person Person
    	// 绑定到 person
    	if c.ShouldBind(&person) == nil {
    		log.Println(person.Name)
    		log.Println(person.Address)
    		log.Println(person.Birthday)
    	}
    
    	c.String(200, "Success")
    }
    

    8.数据验证
    Gin提供了数据检验的方法,Gin的数据验证是和数据绑定结合在一起的,只需要在数据绑定的结构体成员变量的标签添加bingding规则即可。

    // 省略的代码 ...
    
    // 定义的 Login 结构体
    // 该 struct 可以绑定在 Form 和 JSON 中
    // binding:"required" 意思是必要参数。如果未提供,Bind 会返回 error
    type Login struct {
    	User     string `form:"user" json:"user" binding:"required"`
    	Password string `form:"password" json:"password" binding:"required"`
    }
    
    func main() {
    	router := gin.Default()
    
    	// POST 到这个路由一段 JSON, 如 ({"user": "manu", "password": "123"})
    	router.POST("/loginJSON", func(c *gin.Context) {
    		var json Login
    		// 验证数据并绑定
    		if err := c.ShouldBindJSON(&json); err == nil {
    			if json.User == "manu" && json.Password == "123" {
    				c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
    			} else {
    				c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
    			}
    		} else {
    			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    		}
    	})
    
    	// POST 到这个路由一个 Form 表单 (user=manu&password=123)
    	router.POST("/loginForm", func(c *gin.Context) {
    		var form Login
    		// 验证数据并绑定
    		if err := c.ShouldBind(&form); err == nil {
    			if form.User == "manu" && form.Password == "123" {
    				c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
    			} else {
    				c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
    			}
    		} else {
    			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    		}
    	})
    
    	router.Run(":8080")
    }
    

    9.输出响应
    Gin提供了多种常见格式的输出,包括HTML, String, JSON, XML, YAML
    1)String

    // 省略的代码 ...
    
    func Handler(c *gin.Context) {
    	// 使用 String 方法即可
    	c.String(200, "Success")
    }
    
    // 省略的代码 ...
    

    2)JSON, XML, YAML
    gin.H表示实例化一个json对象

    // 省略的代码 ...
    
    func main() {
    	r := gin.Default()
    
    	// gin.H 本质是 map[string]interface{}
    	r.GET("/someJSON", func(c *gin.Context) {
    		// 会输出头格式为 application/json; charset=UTF-8 的 json 字符串
    		c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
    	})
    
    	r.GET("/moreJSON", func(c *gin.Context) {
    		// 直接使用结构体定义
    		var msg struct {
    			Name    string `json:"user"`
    			Message string
    			Number  int
    		}
    		msg.Name = "Lena"
    		msg.Message = "hey"
    		msg.Number = 123
    		// 会输出  {"user": "Lena", "Message": "hey", "Number": 123}
    		c.JSON(http.StatusOK, msg)
    	})
    
    	r.GET("/someXML", func(c *gin.Context) {
    		// 会输出头格式为 text/xml; charset=UTF-8 的 xml 字符串
    		c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
    	})
    
    	r.GET("/someYAML", func(c *gin.Context) {
    		// 会输出头格式为 text/yaml; charset=UTF-8 的 yaml 字符串
    		c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
    	})
    
    	r.Run(":8080")
    }
    
    // 省略的代码 ...
    

    3)HTML
    待实现

    10.其他
    Gin没有提供ORM,CONFIG组件,可以由开发者自己选择。

  • 相关阅读:
    jar包和war包的介绍和区别
    Oracle中rownum的基本用法
    深入理解JVM—JVM内存模型
    Oracle数据库中序列(SEQUENCE)的用法详解
    jvm主内存与工作内存
    jvm虚拟机
    java 冒泡排序
    java二分查找
    java中split()特殊符号"." "|" "*" "" "]"
    java map的实现原理
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/10302727.html
Copyright © 2011-2022 走看看