package libs import ( "fmt" "strings" "git.apinb.com/bsm-sdk/core/errcode" "github.com/go-playground/validator/v10" ) var ( validate *validator.Validate ) func init() { validate = validator.New() // 注册自定义验证规则 registerCustomValidators() } // registerCustomValidators 注册自定义验证器 func registerCustomValidators() { // 注册手机号验证 validate.RegisterValidation("phone", validatePhone) // 注册邮箱验证 validate.RegisterValidation("email_format", validateEmail) } // validatePhone 验证手机号(11位数字,以1开头) func validatePhone(fl validator.FieldLevel) bool { phone := fl.Field().String() // 空字符串由omitempty或required处理,这里返回true if phone == "" { return true } if len(phone) != 11 { return false } if len(phone) > 0 && phone[0] != '1' { return false } for _, char := range phone { if char < '0' || char > '9' { return false } } return true } // validateEmail 验证邮箱格式(简单的邮箱格式验证) func validateEmail(fl validator.FieldLevel) bool { email := fl.Field().String() if email == "" { return true // 允许为空,使用omitempty处理 } parts := strings.Split(email, "@") if len(parts) != 2 { return false } if len(parts[0]) == 0 || len(parts[1]) == 0 { return false } if !strings.Contains(parts[1], ".") { return false } return true } // ValidateStruct 验证结构体,返回格式化的错误信息 func ValidateStruct(s interface{}) error { if err := validate.Struct(s); err != nil { return formatValidationError(err) } return nil } // formatValidationError 格式化验证错误信息 func formatValidationError(err error) error { if validationErrors, ok := err.(validator.ValidationErrors); ok { var errMsg strings.Builder errMsg.WriteString("参数验证失败: ") for i, validationError := range validationErrors { if i > 0 { errMsg.WriteString("; ") } errMsg.WriteString(getFieldErrorMsg(validationError)) } // 返回ErrInvalidArgument错误 return errcode.ErrInvalidArgument } return errcode.ErrInvalidArgument } // getFieldErrorMsg 获取字段错误信息 func getFieldErrorMsg(fe validator.FieldError) string { field := fe.Field() tag := fe.Tag() switch tag { case "required": return fmt.Sprintf("%s 字段为必填项", field) case "min": return fmt.Sprintf("%s 字段长度不能小于 %s", field, fe.Param()) case "max": return fmt.Sprintf("%s 字段长度不能大于 %s", field, fe.Param()) case "len": return fmt.Sprintf("%s 字段长度必须为 %s", field, fe.Param()) case "email_format": return fmt.Sprintf("%s 字段邮箱格式不正确", field) case "phone": return fmt.Sprintf("%s 字段手机号格式不正确(应为11位数字)", field) case "gte": return fmt.Sprintf("%s 字段值必须大于或等于 %s", field, fe.Param()) case "lte": return fmt.Sprintf("%s 字段值必须小于或等于 %s", field, fe.Param()) case "gt": return fmt.Sprintf("%s 字段值必须大于 %s", field, fe.Param()) case "lt": return fmt.Sprintf("%s 字段值必须小于 %s", field, fe.Param()) default: return fmt.Sprintf("%s 字段验证失败 (%s)", field, tag) } }