结构体验证

用gin框架的数据验证,可以不用解析数据,减少if else,会简洁许多。

package main

import (
	"fmt"
	"time"

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

// person
type Person struct {
	//不能位空并且大于10
	Age      int       `form:"age" binding:"required,gt=10"`
	Name     string    `form:"name" binding:"required"`
	Brithday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}

func main() {
	r := gin.Default()
	r.GET("/yangchao", func(ctx *gin.Context) {
		var person Person
		if err := ctx.ShouldBind(&person); err != nil {
			ctx.String(500, fmt.Sprint(err))
			return
		}
		ctx.String(200, fmt.Sprintf("#v", person))
	})
	r.Run()
}

不带参数访问

go语言学习-gin框架参数验证_Time

携带满足要求的参数

go语言学习-gin框架参数验证_Time_02

携带不满足要求参数

go语言学习-gin框架参数验证_自定义_03


自定义验证


package main

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	//"gopkg.in/go-playground/validator.v9"
)

/*
对绑定的解析到结构体上的参数,自定义验证功能
对url的接收参数进行判断,判断用户名是否为root,如果是root通过否则返回false
*/

type Login struct {
	User     string `uri:"user" validate:"CheckName"`
	Password string `uri:"password"`
}

//自定义验证函数

func CheckName(fl validator.FieldLevel) bool {
	if fl.Field().String() != "root" {
		return false
	}
	return true
}

func main() {
	r := gin.Default()
	validate := validator.New()
	r.GET("/:user/:password", func(ctx *gin.Context) {
		var login Login
		//注册自定义函数,与struct tag关联
		err := validate.RegisterValidation("ChecName", CheckName)
		if err := ctx.ShouldBindUri(&login); err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
			return

		}
		err = validate.Struct(login)
		if err != nil {
			for _, err := range err.(validator.ValidationErrors) {
				fmt.Println(err)
			}
			return
		}
		fmt.Println("success")
	})
	r.Run()
}
package main

import (
	"net/http"
	"reflect"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
)

// Booking 包含了绑定和验证数据
type Booking struct {
	//定义一个预约时间大于今天的时间
	CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
	//gtfield=Checkin退出时间大于预约的时间
	CheckOut time.Time `form:"check_out" binding:"required,grfield=CheckIn" time_format:"2006-01-02"`
}

func bookableDate(
	v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
	field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
	//field.Interface().(time.Time)获取参数值并且转换为时间格式
	if date, ok := field.Interface().(time.Time); ok {
		today := time.Now()
		if today.Unix() > date.Unix() {
			return false
		}
	}
	return true
}

func GetBookable(ctx *gin.Context) {
	var b Booking
	if err := ctx.ShouldBindWith(&b, binding.Query); err == nil {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "Booking dates are valid!",
		})
	} else {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
	}
}

func main() {
	route := gin.Default()
	//注册验证
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		//绑定第一个参数是验证的函数第二个参数是自定义的验证函数
		v.RegisterValidation("bookabledate", bookableDate)
	}

	route.GET("/yangchao", GetBookable)
	route.Run()
}

自定义验证说明

Validator 是基于 tag(标记)实现结构体和单个字段的值验证库,它包含以下功能:

  • 使用验证 tag(标记)或自定义验证器进行跨字段和跨结构体验证。
  • 关于 slice、数组和 map,允许验证多维字段的任何或所有级别。
  • 能够深入 map 键和值进行验证。
  • 通过在验证之前确定接口的基础类型来处理类型接口。
  • 处理自定义字段类型(如 sql 驱动程序 Valuer)。
  • 别名验证标记,它允许将多个验证映射到单个标记,以便更轻松地定义结构体上的验证。
  • 提取自定义的字段名称,例如,可以指定在验证时提取 JSON 名称,并在生成的 FieldError 中使用该名称。
  • 可自定义 i18n 错误消息。
  • Web 框架 gin 的默认验证器。

以下是常用的标签

标签

描述

eq

等于

gt

大于

gte

大于等于

lt

小于

lte

小于等于

ne

不等于

max

最大值

min

最小值

oneof

其中一个

required

必需的

unique

唯一的

isDefault

默认值

len

长度

email

邮箱格式

日志文件

package main

import (
    "io"
    "os"

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

func main() {
    gin.DisableConsoleColor()

    // Logging to a file.
    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f)

    // 如果需要同时将日志写入文件和控制台,请使用以下代码。
    // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })
    r.Run()
}