虽然gvalid已经内置了常见的数十种校验规则,但是在部分业务场景下我们需要自定义校验规则,特别是一些可以重复使用的业务相关的校验规则。当然,gvalid如此的强大,她已经为您考虑得如此周全。

校验规则注册:

  1. // RegisterRule registers custom validation rule and function for package.
  2. // It returns error if there's already the same rule registered previously.
  3. func RegisterRule(rule string, f RuleFunc) error

校验方法定义:

  1. // RuleFunc is the custom function for data validation.
  2. // The parameter <rule> specifies the validation rule string, like "required", "between:1,100", etc.
  3. // The parameter <value> specifies the value for this rule to validate.
  4. // The parameter <message> specifies the custom error message or configured i18n message for this rule.
  5. // The parameter <params> specifies all the parameters that needs. You can ignore parameter <params> if
  6. // you do not really need it in your custom validation rule.
  7. type RuleFunc func(rule string, value interface{}, message string, params map[string]interface{}) error

简要说明:

  1. 您需要按照RuleFunc类型的方法定义,实现一个您需要的校验方法,随后使用RegisterRule注册到gvalid模块中全局管理。该注册逻辑往往是在程序初始化时执行。该方法在对数据进行校验时将会被自动调用,方法返回nil表示校验通过,否则应当返回一个非空的error类型值。
  2. 参数说明:
    • rule参数表示当前的校验规则,包含规则的参数,例如:required, between:1,100, length:6等等。
    • value参数表示被校验的数据值,注意类型是一个interface{},因此您可以传递任意类型的参数,并在校验方法内部按照程序使用约定自行进行转换(往往使用gconv模块实现转换)。
    • message参数表示在校验失败后返回的校验错误提示信息,往往在struct定义时使用gvalid tag来通过标签定义。
    • params参数表示校验时传递的所有参数,例如校验的是一个map或者struct时,往往在联合校验时有用。

注意事项:从性能考虑,自定义规则的注册方法不支持并发调用,您需要在程序启动时进行注册(例如在boot包中处理),无法在运行时动态注册,否则会产生并发安全问题。

示例1,用户唯一性规则

在用户注册时,我们往往需要校验当前用户提交的名称/账号是否唯一,因此我们可以注册一个unique-name的全局规则来实现。

  1. registerRule := "unique-name"
  2. gvalid.RegisterRule(registerRule, func(rule string, value interface{}, message string, params map[string]interface{}) error {
  3. var (
  4. id = gconv.Int(params["Id"])
  5. name = gconv.String(value)
  6. )
  7. n, err := g.Table("user").Where("id != ? and name = ?", id, name).Count()
  8. if err != nil {
  9. return err
  10. }
  11. if n > 0 {
  12. return errors.New(message)
  13. }
  14. return nil
  15. })
  16. type User struct {
  17. Id int
  18. Name string `v:"required|unique-name # 请输入用户名称|用户名称已被占用"`
  19. Pass string `v:"required|length:6,18"`
  20. }
  21. user := &User{
  22. Id: 1,
  23. Name: "john",
  24. Pass: "123456",
  25. }
  26. err := gvalid.CheckStruct(user, nil)
  27. fmt.Println(err.Error())
  28. // Output:
  29. // 用户名称已被占用

示例2,自定义实现required规则

默认情况下,gvalid的内置规则是不支持mapslice类型的required规则校验,因此我们可以自行实现,然后覆盖原有规则。其他的规则也可以按照此逻辑自定义覆盖。

  1. registerRule := "required"
  2. gvalid.RegisterRule(registerRule, func(rule string, value interface{}, message string, params map[string]interface{}) error {
  3. reflectValue := reflect.ValueOf(value)
  4. if reflectValue.Kind() == reflect.Ptr {
  5. reflectValue = reflectValue.Elem()
  6. }
  7. isEmpty := false
  8. switch reflectValue.Kind() {
  9. case reflect.Bool:
  10. isEmpty = !reflectValue.Bool()
  11. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  12. isEmpty = reflectValue.Int() == 0
  13. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  14. isEmpty = reflectValue.Uint() == 0
  15. case reflect.Float32, reflect.Float64:
  16. isEmpty = math.Float64bits(reflectValue.Float()) == 0
  17. case reflect.Complex64, reflect.Complex128:
  18. c := reflectValue.Complex()
  19. isEmpty = math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
  20. case reflect.String, reflect.Map, reflect.Array, reflect.Slice:
  21. isEmpty = reflectValue.Len() == 0
  22. }
  23. if isEmpty {
  24. return errors.New(message)
  25. }
  26. return nil
  27. })
  28. fmt.Println(gvalid.Check("", "required", "It's required"))
  29. fmt.Println(gvalid.Check([]string{}, "required", "It's required"))
  30. fmt.Println(gvalid.Check(map[string]int{}, "required", "It's required"))
  31. gvalid.DeleteRule(rule)
  32. fmt.Println("rule deleted")
  33. fmt.Println(gvalid.Check("", "required", "It's required"))
  34. fmt.Println(gvalid.Check([]string{}, "required", "It's required"))
  35. fmt.Println(gvalid.Check(map[string]int{}, "required", "It's required"))
  36. // Output:
  37. // It's required
  38. // It's required
  39. // It's required
  40. // rule deleted
  41. // It's required