gin框架中的参数验证
结构体验证
用gin框架的数据验证,可以不用解析数据,减少if else,会简洁许多。
- 处理请求方法
func structValidator(context *gin.Context) {
var person Person
if err := context.ShouldBind(&person); err != nil {
fmt.Println(err)
context.String(http.StatusBadRequest, "failed")
return
}
context.JSON(http.StatusOK, &person)
}
- 验证结构体
type Person struct {
// 不能为空并且大于10
Age int `json:"age" form:"age" binding:"required,gt=10"`
Name string `json:"name" form:"name" binding:"required"`
Birthday time.Time `json:"birthday" form:"birthday" time_format:"2006-01-02 15:04:05" time_utc:"0"`
}
自定义验证 V10版本
依赖:github.com/go-playground/validator/v10
type Person struct {
// 不能为空并且大于10
Age int `json:"age" form:"age" binding:"required,gt=10"`
// 2、在参数 binding 上使用自定义的校验方法函数注册时候的名称
Name string `json:"name" form:"name" binding:"NotNullAndAdmin"`
Birthday time.Time `json:"birthday" form:"birthday" time_format:"2006-01-02"`
}
func NotNullAndAdmin(fl validator.FieldLevel) bool {
if value, ok := fl.Field().Interface().(string); ok {
// 字段不能为空,并且不等于 admin
return value != "" && !("admin" == value)
}
return false
}
func RegisterValidator() {
// 将我们自定义的校验方法注册到validator中
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 这里的 key 和 fn 可以不一样最终在 struct 使用的是 key
v.RegisterValidation("NotNullAndAdmin", NotNullAndAdmin)
}
}
func main() {
// 注册验证器
blog.RegisterValidator()
}
自定义验证器 V8版本
点击查看代码
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"gopkg.in/go-playground/validator.v8"
"net/http"
"reflect"
"time"
)
//binding 绑定一些验证请求参数,自定义标签bookabledate表示可预约的时期
type Booking struct {
CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckOut,bookabledate" time_format:"2006-01-02"`
}
//定义bookabledate标签对应的验证方法
func bookableDate(
v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
if date, ok := field.Interface().(time.Time); ok {
today := time.Now()
if date.Unix() > today.Unix() {
return true
}
}
return false
}
func main() {
route := gin.Default()
//将验证方法注册到验证器中
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("bookabledate", bookableDate)
}
route.GET("/bookable", getBookable)
route.Run(":8080")
}
func getBookable(c *gin.Context) {
var b Booking
if err := c.ShouldBindWith(&b, binding.Query); err == nil {
c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}
V10 版本示例2
func RegisterValidator() {
// 将我们自定义的校验方法注册到validator中
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 这里的 key 和 fn 可以不一样最终在 struct 使用的是 key
v.RegisterValidation("NotNullAndAdmin", NotNullAndAdmin)
v.RegisterValidation("bookableDate", bookableDate)
}
}
type Booking struct {
// 定义一个预约的时间大于今天的时间
CheckIn time.Time `json:"check_in" binding:"required,bookableDate" time_format:"2006-01-02"`
// gtfield=CheckIn退出的时间大于预约的时间
CheckOut time.Time `json:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
}
func bookableDate(fl validator.FieldLevel) bool {
if v, ok := fl.Field().Interface().(time.Time); ok {
currentTime := time.Now().Unix()
if currentTime > v.Unix() {
return false
}
}
return true
}
请求参数:
{
"check_in": "2021-12-13T8:16:25Z", // UTC时区
"check_out": "2021-12-13T16:16:26+08:00" // 中国:东八时区
}