9

gin请求数据校验

 3 years ago
source link: https://studygolang.com/articles/28300
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

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

优化前代码

代码如下:

UZbA3me.png!web

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

优化代码

这里使用 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的数据请求校验了,接下来看下优化后的代码。

优化后代码

iyYbQjA.png!web

只需要正常使用 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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK