Go开源宝藏Web框架 GIN 专场 (含思维导图) | 持续更新

Posted 小生凡一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go开源宝藏Web框架 GIN 专场 (含思维导图) | 持续更新相关的知识,希望对你有一定的参考价值。

写在前面

本人只是一个Go语言的初学者,这篇总结只是把我平常经常用到的都总结起来而已。
具体详细的内容建议到去GIN的中文文档查看。
当然这篇文章也会持续更新,记录我的Web框架操练过程
这篇文章也会持续更新哒

思维导图

想获取原图或是.xmind格式可在文末扫描并回复宝藏GIN


github.com/gin-gonic/gin

1. 路由

1.1 基本路由

gin框架中

  • gin.Default() 创建路由实例
  • 给出了 gin.Context,封装了requestresponse
package main

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

func main() {
	r := gin.Default()  // 使用Default创建路由
	r.GET("/", func(c *gin.Context) {       // 这个c就是上下文,这个路由接收GET请求
		c.String(http.StatusOK, "hello world")  // 返回状态码和数据
	})
	_ = r.Run(":8000")	//监听端口默认为8080
}

简单几行代码,就能实现一个非常简单的小网页了啦~

1.2 RESTful 路由

  • gin支持RESTful风格的API。
  • RESTful即Representational State Transfer的缩写。直接翻译的意思是表现层状态转化,是一种互联网应用程序的API设计理念:URL定位资源,用HTTP描述操作。
  • 是目前最主流的前后端交互规范形式。
	r.POST("carts", api.CreateCart)    // POST请求,一般提交表单
	r.GET("carts/:id", api.ShowCarts)  //GET请求,一般获取数据
	r.PUT("carts", api.UpdateCart)     //PUT请求,一般修改数据
	r.DELETE("carts", api.DeleteCart)  // DELETE请求,一般删除数据

1.3 参数接收

  • 获取URL中的参数,一般用于GETDELETE请求。

Gin 中提供了.Param进行参数的获取。

package main

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

func main() {
	r := gin.Default() 
	r.GET("/user/:name/:action", func(c *gin.Context) {
		name := c.Param("name") // 使用Param可以获取路由URL里面的数据
		action := c.Param("action")
		c.String(http.StatusOK, name+" rush "+action)
	})
	_ = r.Run(":8000")
}
  • 获取表单参数,一般用于POSTPUT请求。

Gin提供了.PostForm方法获取Form表单的值。

package main

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

func main() {
	r := gin.Default()
	r.POST("/form", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")
		c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s", username, password))
	})
	_ = r.Run(":8000")
}

1.4 文件上传与下载

1.4.1 上传

  • 提供了.FormFile来获取文件
package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.POST("/upload", func(c *gin.Context) {
        file, err := c.FormFile("file")  // file是参数名称
        if err != nil {
            c.String(500, "上传图片出错")   //出错就会返回这个
        }
        c.SaveUploadedFile(file, file.Filename) // 保存文件
        c.String(http.StatusOK, file.Filename)  // 返回状态码
    })
    _ = r.Run(":8000")
}

1.4.2 下载

1.5 路由拆分

我们一般来说,会把这个路由拆分成URL处理函数。这样能高效管理我们的框架逻辑。

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

func helloHandler(c *gin.Context) {  // 把处理函数放在这里,可以处理一些复杂的业务
    c.JSON(http.StatusOK, gin.H {
        "message": "Hello World!",   // 通过这个 gin.H{} 进行json格式的返回
    })
}
 
// Router 配置路由信息
func Router() *gin.Engine {
    r := gin.Default()
    r.GET("/hello", helloHandler) // 这样这个路由就比较简洁了。
    return r
}

2. 数据绑定

2.1 json数据格式

  • 定义接收数据的结构体

binding:"required"修饰的字段,是必须有的,没有是会报错的。后面可以跟着限制,满足限制才不会报错。

type Product struct {
	Name          string `form:"name" json:"name"`
	CategoryID    int    `form:"category_id" json:"category_id"`
	Title         string `form:"title" json:"title" binding:"required,min=2,max=100"`
	Info          string `form:"info" json:"info" binding:"max=1000"`
	ImgPath       string `form:"img_path" json:"img_path"`
	Price         string `form:"price" json:"price"`
	DiscountPrice string `form:"discount_price" json:"discount_price"`
	OnSale 		  string `form:"on_sale" json:"on_sale"`
	Num 		  string `form:"num" json:"num"`
}

gin框架中提供了一个ShouldBindJSON方法,这样就能可以把json格式解析到结构体中。

func helloHandler(c *gin.Context) {  // 把处理函数放在这里,可以处理一些复杂的业务
    var data Product 
    if err := c.ShouldBindJSON(&data); err != nil {  
    		// 进行数据的绑定,这样传过来的数据就会传入这个data当中
         // gin.H封装了生成json数据的工具
         c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) // 返回错误信息
         return
      }
    c.JSON(http.StatusOK, gin.H{"status": "200"})
}
 
// Router 配置路由信息
func Router() *gin.Engine {
    r := gin.Default()
    r.GET("/hello", helloHandler) // 这样这个路由就比较简洁了。
    return r
}

2.2 form表单数据

同样的我们使用2.1中的Product结构体,注意一定要在结构体中,用tags标志form格式

上面的那个Product结构体是用tags标志了form格式和json格式的,所以两个都能用。

func helloHandler(c *gin.Context) {  // 把处理函数放在这里,可以处理一些复杂的业务
    var data Product 
    if err := c.Bind(&data); err != nil {  
    		// Bind()默认解析并绑定form格式,这样传过来的数据就会传入这个data当中
         c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) // 返回错误信息
         return
      }
    c.JSON(http.StatusOK, gin.H{"status": "200"})
}

2.3 URI

type Product struct {
	Name          string `form:"name" json:"name" uri:"name”`
	CategoryID    int    `form:"category_id" json:"category_id" uri:"category_id"`
	Title         string `form:"title" json:"title" uri:“title binding:"required,min=2,max=100"`
	Info          string `form:"info" json:"info" uri:“info binding:"max=1000"`
	ImgPath       string `form:"img_path" json:"img_path" uri:"img_path"`
	Price         string `form:"price" json:"price" uri:“price`
	DiscountPrice string `form:"discount_price" json:"discount_price" uri:"discount_price"`
	OnSale 		  string `form:"on_sale" json:"on_sale" uri:"on_sale"`
	Num 		  string `form:"num" json:"num" uri:"num"`
}

gin中提供了ShouldBindUri方法进行绑定

func helloHandler(c *gin.Context) {  // 把处理函数放在这里,可以处理一些复杂的业务
    var data Product 
    if err := c.ShouldBindUri(&data); err != nil {  
         c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) // 返回错误信息
         return
      }
    c.JSON(http.StatusOK, gin.H{"status": "200"})
}

无论是ShouldBindJSON还是Bind还是ShouldBindUri
不过我个人比较喜欢用c.ShouldBind()这种,看个人喜欢吧~

3. 参数验证

3.1 普通情况

type User struct {
    Phone    string   `form:"phone" binding:"required,gt=10"`  //不能为空并且大于10
    Name     string    `form:"name" binding:"required"`
    Birthday time.Time `form:"birthday" time_format:"2006-01-02"` 
    // 满足格式才能接收,减少了if-else的判断
}

3.2 自定义情况

使用 gopkg.in/go-playground/validator.v8

  • 在结构体上,绑定这个NotNullAndAdmin
type User struct {
	Phone    string   `form:"phone" binding:"required,gt=10"`  //不能为空并且大于10
	Name     string    `form:"name" binding:"NotNullAndAdmin"`  // 自定义一个验证
	Birthday time.Time `form:"birthday" time_format:"2006-01-02"`
	// 满足格式才能接收,减少了if-else的判断
}
  • 编写自定义方法
func nameNotNullAndAdmin(v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
	if value, ok := field.Interface().(string); ok {
		return value != "" && !("admin" == value)// 字段不能为空,并且不等于  admin
	}
	return true
}
  • 把我们的自定义注册到validator中就好了
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		_ = v.RegisterValidation("NotNullAndAdmin", nameNotNullAndAdmin)  //注册定义的验证方法
	}

4. 渲染

4.1 数据的响应

  • Json 前后端主流的交互数据格式,我自己也是经常用这个。
func main() {
	r := gin.Default()
	r.GET("/json",JsonHandler)
	_ = r.Run(":8000")
}

func JsonHandler(c *gin.Context)  {
	c.JSON(200, gin.H{"message": "HelloJson", "status": 200})
}
  • Struct
func main() {
	r := gin.Default()	
	r.GET("/struct", StructHandler)
	_ = r.Run(":8000")
}

func StructHandler(c *gin.Context) {
	var msg struct {
		Name    string
		Message string
		Number  int
	}
	msg.Name = "FanOne"
	msg.Message = "Golang"
	msg.Number = 10001
	c.JSON(200, msg)
}
  • XML
func main() {
	r := gin.Default()	
	r.GET("/xml", XMLHandler)
	_ = r.Run(":8000")
}

func XMLHandler(c *gin.Context)  {
	c.XML(200, gin.H{"message": "HelloXml"})
}
  • YAML
func main() {
	r := gin.Default()	
	r.GET("/yaml", YAMLHandler)
	_ = r.Run(":8000")
}

func YAMLHandler(c *gin.Context)  {
	c.YAML(200, gin.H{"message": "HelloYaml"})
}
  • ProtoBuf 这几年很火的数据格式
func main() {
	r := gin.Default()	
	r.GET("/protobuf", ProtoBufHandler)
	_ = r.Run(":8000")
}

func ProtoBufHandler(c *gin.Context)  {
	reps := []int64{int64(1), int64(2)}
	// 定义数据
	label := "label"
	// 传protobuf格式数据
	data := &protoexample.Test{
		Label: &label,
		Reps:  reps,
	}
	c.ProtoBuf(200, data)
}

4.2 模板渲染

  • gin支持加载html模板, 然后根据模板参数进行配置并返回相应的数据,本质上就是字符串替换
  • LoadHTMLGlob()方法可以加载模板文件
  • Static方法可以加载静态文件
  • 加载HTML模板
func main() {
    r := gin.Default()
    r.LoadHTMLGlob("tempate/*")  // 加载你的模板文件 就是html文件嗷
    r.GET("/index", func(c *gin.Context) {
        c.HTML(http.StatusOK, "index.html", gin.H{"msg": "HelloWorld", "status": "200"})
    })
    r.Run()
}
  • 加载Static静态文件
func main() {
    r := gin.Default()    
    r.Static("/assets", "./assets") // 需要定义一个静态文件目录
    r.GET("/index", func(c *gin.Context) {
        c.HTML(http.StatusOK, "index.html", gin.H{"msg": "HelloWorld", "status": "200"})
    })
    r.Run()
}

这两个其实很少用,因为基本都是前后端分离,所以就很少去用这些东西哒。

使用了这些意味着前后页面也在后端这边,高度耦合,所以不推荐使用嗷~

4.3 重定向

gin包中有c.Redirect可以使得跳转的时候重新跳到 baidu.com 这个页面

func main() {
    r := gin.Default()
    r.GET("/index", func(c *gin.Context) {
        c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com")
    })
    r.Run()
}

5. 中间件

这里会单独出一些中间件的介绍的,当然只是我自己经常用的到一些而已。

  • CORS
  • JWT-Go
  • Logging

6. 会话控制

6.1 Cookie

  • HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出。
  • Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思。
  • Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求。
  • Cookie由服务器创建,并发送给浏览器,最终由浏览器保存
  • 服务端发送cookie给客户端,客户端请求时携带cookie

Cookie的问题有很多,比如说不安全明文增加带宽消耗cookie有上限等等。

6.2 Sessions

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。

客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session

客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"

为自定义session后端提供cookie和文件系统session以及基础结构。

主要功能是:

  • 简单的API:将其用作设置签名(以及可选的加密)cookie的简便方法。
  • 内置的后端可将session存储在cookie文件系统中
  • Flash消息:一直持续读取的session值
  • 切换session持久性(又称“记住我”)和设置其他属性的便捷方法。
  • 旋转身份验证加密密钥的机制。
  • 每个请求有多个session,即使是使用不同的后端也是如此。
  • 自定义session后端的接口和基础结构:可以使用通用API检索并批量保存来源不同的session。
	store := cookie.NewStore([]byte("something-very-secret"))  // 存储
	r.Use(sessions.Sessions("mysession", store))   // 其实这也算是一个中间件

7. 日志模块

Gin有提供自己默认的日志!

  • 如果不指定的话,是把请求信息直接输出到控制台的。

  • 把这个代码加到在初始化文件那里就行了。就不会输出在控制台了,而是会输出到.log文件当中

    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f)
    // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
  • 如果需要同时将日志写入文件和控制台,那就是这个代码
    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

以上是关于Go开源宝藏Web框架 GIN 专场 (含思维导图) | 持续更新的主要内容,如果未能解决你的问题,请参考以下文章

Go开源宝藏Golang 爬虫 | 整点新花样

Go语言web框架 gin

Go语言系列第三方框架和库——GIN:GIN介绍

GOGin

Go实战Gin + Gorm 基于RESTful API 的简单备忘录 | 含接口文档

Go的web框架——Gin初识