zoukankan      html  css  js  c++  java
  • gin请求数据校验

    前言

    最近优化gin+vue的前后端分离项目代码时候,发现代码中对请求数据的校验比较繁琐,于是想办法简化它。最终我发现了go-playground/validator开源库很好用。

    优化前代码

    代码如下:

    发现每个方法都这样校验数据,很繁琐。

    优化代码

    这里使用go-playground/validator开源库来简化请求校验。

    1.安装go-playground/validator

    # 使用 Go Modules
    go env -w GO111MODULE=on
    # 安装 go-playground/validator
    go get github.com/go-playground/validator/v10
    

    注意:v10版本是使用Go Modules,运行 go get github.com/go-playground/validator/v10前需要确保GO111MODULE=on,不然会报:cannot find package "github.com/go-playground/validator/v10"

    2.实现StructValidator接口的两个方法

    StructValidator是需要实现的最基本的接口,作为验证引擎来确保请求的正确性。

    type StructValidator interface {
    
    	ValidateStruct(interface{}) error
    	
    	Engine() interface{}
    }
    
    • ValidateStruct :如果接收到的类型是一个结构体或指向结构体的指针,则执行验证。
    • Engine: 返回支持StructValidator实现的底层验证引擎。

    实现接口:

    package validator
    
    import (
    	"reflect"
    	"sync"
    
    	"github.com/gin-gonic/gin/binding"
    	"github.com/go-playground/validator/v10"
    )
    
    type DefaultValidator struct {
    	once     sync.Once
    	validate *validator.Validate
    }
    
    var _ binding.StructValidator = &DefaultValidator{}
    
    // ValidateStruct 如果接收到的类型是一个结构体或指向结构体的指针,则执行验证。
    func (v *DefaultValidator) ValidateStruct(obj interface{}) error {
    	if kindOfData(obj) == reflect.Struct {
    
    		v.lazyinit()
    
    		//如果传递不合规则的值,则返回InvalidValidationError,否则返回nil。
            ///如果返回err != nil,可通过err.(validator.ValidationErrors)来访问错误数组。
    		if err := v.validate.Struct(obj); err != nil {
    			return err
    		}
    	}
    	return nil
    }
    // Engine 返回支持`StructValidator`实现的底层验证引擎
    func (v *DefaultValidator) Engine() interface{} {
    	v.lazyinit()
    	return v.validate
    }
    
    func (v *DefaultValidator) lazyinit() {
    	v.once.Do(func() {
    		v.validate = validator.New()
    		v.validate.SetTagName("validate")
    		// //v8版本,v8版本使用"binding"
    		// v.validate.SetTagName("binding")
    	})
    }
    
    func kindOfData(data interface{}) reflect.Kind {
    	value := reflect.ValueOf(data)
    	valueType := value.Kind()
    
    	if valueType == reflect.Ptr {
    		valueType = value.Elem().Kind()
    	}
    	return valueType
    }
    

    3.使用该验证引擎

    修改model,添加validate验证

    type Article struct {
    	ID            int       `gorm:"primary_key" json:"id"`
    	State         int       `json:"state" validate:"min=0,max=1"`
    	TagID         int       `json:"tag_id" validate:"gt=0"`
    	Title         string    `json:"title" validate:"required"`
    	Desc          string    `json:"desc" validate:"required"`
    	Content       string    `json:"content" validate:"required"`
    	CoverImageURL string    `json:"cover_image_url"`
    	CreatedBy     string    `json:"created_by" validate:"required"`
    	ModifiedBy    string    `json:"modified_by"`
    }
    

    最后,只需在main函数中添加这行代码:

    package main
    
    import (
        "github.com/gin-gonic/gin/binding"
    	"github.com/bingjian-zhu/gin-vue-admin/common/validator"
    )
    func main() {
    
    	binding.Validator = new(validator.DefaultValidator)
    
    	// regular gin logic
    }
    

    以上,我们就完成了gin的数据请求校验了,接下来看下优化后的代码。

    优化后代码

    只需要正常使用c.Bing(model)就可以对请求的数据进行校验了,代码简化了许多。

    常用校验规则介绍

    type Test struct {
    	ID          int    `validate:"required"`             //数字确保不为0
    	Name        string `validate:"required,min=1,max=8"` //字符串确保不为"",且长度 >=1 && <=8 (min=1,max=8等于gt=0,lt=9)
    	Value       string `validate:"required,gte=1,lte=8"` //字符串确保不为"",且长度 >=1 && <=8
    	Status      int    `validate:"min=1,max=10"`         //最小为0,最大为10(min=0,max=10等于gt=0,lt=11)
    	PhoneNumber string `validate:"required,len=11"`      //不为""且长度为11
    	Time        string `validate:"datetime=2006-01-02"`  //必须如2006-01-02的datetime格式
    	Color       string `validate:"oneof=red green"`      //是能是red或者green
    	Size        int    `validate:"oneof=37 39 41"`       //是能是37或者39或者41
    	Email       string `validate:"email"`                //必须邮件格式
    	JSON        string `validate:"json"`                 //必须json格式
    	URL         string `validate:"url"`                  //必须url格式
    	UUID        string `validate:"uuid"`                 //必须uuid格式
    }
    

    更多校验规则可以阅读源码文档

    总结

    go-playground/validator开源库把gin的请求校验简单化了,使得我们代码更简单易读。

    以上只是对结构体做请求校验,对于非结构体的请求校验,用老办法

    import "github.com/astaxie/beego/validation"
    
    func (a *Article) GetArticle(c *gin.Context) {
    	id, _ := strconv.Atoi(c.Param("id"))
    	valid := validation.Validation{}
    	valid.Min(id, 1, "id").Message("ID必须大于0")
    	var data *models.Article
    	code := codes.InvalidParams
    	if !valid.HasErrors() {
    		data = a.Service.GetArticle(id)
    		code = codes.SUCCESS
    	} else {
    		for _, err := range valid.Errors {
    			a.Log.Info("err.key: %s, err.message: %s", err.Key, err.Message)
    		}
    	}
    	RespData(c, http.StatusOK, code, data)
    }
    

    源码地址:https://github.com/Bingjian-Zhu/gin-vue-admin

  • 相关阅读:
    网上购物记录(2011淘宝大甩卖)
    心理学上最诡异的23张图!!
    三字念什么
    哥德尔不完备定理
    又要新的开始了(续)
    第一次接触计算机语言的经历
    哥德尔不完备性定理——从数学危机到哲学危机
    google (精简版)
    贴吧回复
    在轻松的环境中工作
  • 原文地址:https://www.cnblogs.com/FireworksEasyCool/p/12794311.html
Copyright © 2011-2022 走看看