239 lines
6.3 KiB
Go
239 lines
6.3 KiB
Go
|
|
package validator
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"net/url"
|
|||
|
|
"regexp"
|
|||
|
|
"strings"
|
|||
|
|
|
|||
|
|
"github.com/go-playground/validator/v10"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// BusinessValidator 业务验证器
|
|||
|
|
type BusinessValidator struct {
|
|||
|
|
validator *validator.Validate
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewBusinessValidator 创建业务验证器
|
|||
|
|
func NewBusinessValidator() *BusinessValidator {
|
|||
|
|
validate := validator.New()
|
|||
|
|
RegisterCustomValidators(validate)
|
|||
|
|
|
|||
|
|
return &BusinessValidator{
|
|||
|
|
validator: validate,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateStruct 验证结构体
|
|||
|
|
func (bv *BusinessValidator) ValidateStruct(data interface{}) error {
|
|||
|
|
return bv.validator.Struct(data)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateField 验证单个字段
|
|||
|
|
func (bv *BusinessValidator) ValidateField(field interface{}, tag string) error {
|
|||
|
|
return bv.validator.Var(field, tag)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 以下是具体的业务验证方法,可以在业务逻辑中直接调用
|
|||
|
|
|
|||
|
|
// ValidatePhone 验证手机号
|
|||
|
|
func (bv *BusinessValidator) ValidatePhone(phone string) error {
|
|||
|
|
if phone == "" {
|
|||
|
|
return fmt.Errorf("手机号不能为空")
|
|||
|
|
}
|
|||
|
|
matched, _ := regexp.MatchString(`^1[3-9]\d{9}$`, phone)
|
|||
|
|
if !matched {
|
|||
|
|
return fmt.Errorf("手机号格式不正确")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidatePassword 验证密码强度
|
|||
|
|
func (bv *BusinessValidator) ValidatePassword(password string) error {
|
|||
|
|
if password == "" {
|
|||
|
|
return fmt.Errorf("密码不能为空")
|
|||
|
|
}
|
|||
|
|
if len(password) < 8 {
|
|||
|
|
return fmt.Errorf("密码长度不能少于8位")
|
|||
|
|
}
|
|||
|
|
hasUpper := regexp.MustCompile(`[A-Z]`).MatchString(password)
|
|||
|
|
hasLower := regexp.MustCompile(`[a-z]`).MatchString(password)
|
|||
|
|
hasDigit := regexp.MustCompile(`\d`).MatchString(password)
|
|||
|
|
|
|||
|
|
if !hasUpper {
|
|||
|
|
return fmt.Errorf("密码必须包含大写字母")
|
|||
|
|
}
|
|||
|
|
if !hasLower {
|
|||
|
|
return fmt.Errorf("密码必须包含小写字母")
|
|||
|
|
}
|
|||
|
|
if !hasDigit {
|
|||
|
|
return fmt.Errorf("密码必须包含数字")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateUsername 验证用户名
|
|||
|
|
func (bv *BusinessValidator) ValidateUsername(username string) error {
|
|||
|
|
if username == "" {
|
|||
|
|
return fmt.Errorf("用户名不能为空")
|
|||
|
|
}
|
|||
|
|
matched, _ := regexp.MatchString(`^[a-zA-Z][a-zA-Z0-9_]{2,19}$`, username)
|
|||
|
|
if !matched {
|
|||
|
|
return fmt.Errorf("用户名格式不正确,只能包含字母、数字、下划线,且必须以字母开头,长度3-20位")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateSocialCreditCode 验证统一社会信用代码
|
|||
|
|
func (bv *BusinessValidator) ValidateSocialCreditCode(code string) error {
|
|||
|
|
if code == "" {
|
|||
|
|
return fmt.Errorf("统一社会信用代码不能为空")
|
|||
|
|
}
|
|||
|
|
matched, _ := regexp.MatchString(`^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$`, code)
|
|||
|
|
if !matched {
|
|||
|
|
return fmt.Errorf("统一社会信用代码格式不正确,必须是18位统一社会信用代码")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateIDCard 验证身份证号
|
|||
|
|
func (bv *BusinessValidator) ValidateIDCard(idCard string) error {
|
|||
|
|
if idCard == "" {
|
|||
|
|
return fmt.Errorf("身份证号不能为空")
|
|||
|
|
}
|
|||
|
|
matched, _ := regexp.MatchString(`^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[\dXx]$`, idCard)
|
|||
|
|
if !matched {
|
|||
|
|
return fmt.Errorf("身份证号格式不正确,必须是18位身份证号")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateUUID 验证UUID
|
|||
|
|
func (bv *BusinessValidator) ValidateUUID(uuid string) error {
|
|||
|
|
if uuid == "" {
|
|||
|
|
return fmt.Errorf("UUID不能为空")
|
|||
|
|
}
|
|||
|
|
matched, _ := regexp.MatchString(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, uuid)
|
|||
|
|
if !matched {
|
|||
|
|
return fmt.Errorf("UUID格式不正确")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateURL 验证URL
|
|||
|
|
func (bv *BusinessValidator) ValidateURL(urlStr string) error {
|
|||
|
|
if urlStr == "" {
|
|||
|
|
return fmt.Errorf("URL不能为空")
|
|||
|
|
}
|
|||
|
|
_, err := url.ParseRequestURI(urlStr)
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("URL格式不正确: %v", err)
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateProductCode 验证产品代码
|
|||
|
|
func (bv *BusinessValidator) ValidateProductCode(code string) error {
|
|||
|
|
if code == "" {
|
|||
|
|
return fmt.Errorf("产品代码不能为空")
|
|||
|
|
}
|
|||
|
|
matched, _ := regexp.MatchString(`^[a-zA-Z0-9_-]{3,50}$`, code)
|
|||
|
|
if !matched {
|
|||
|
|
return fmt.Errorf("产品代码格式不正确,只能包含字母、数字、下划线、连字符,长度3-50位")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateEmail 验证邮箱
|
|||
|
|
func (bv *BusinessValidator) ValidateEmail(email string) error {
|
|||
|
|
if email == "" {
|
|||
|
|
return fmt.Errorf("邮箱不能为空")
|
|||
|
|
}
|
|||
|
|
matched, _ := regexp.MatchString(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`, email)
|
|||
|
|
if !matched {
|
|||
|
|
return fmt.Errorf("邮箱格式不正确")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateSortOrder 验证排序方向
|
|||
|
|
func (bv *BusinessValidator) ValidateSortOrder(sortOrder string) error {
|
|||
|
|
if sortOrder == "" {
|
|||
|
|
return nil // 允许为空
|
|||
|
|
}
|
|||
|
|
if sortOrder != "asc" && sortOrder != "desc" {
|
|||
|
|
return fmt.Errorf("排序方向必须是 asc 或 desc")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidatePrice 验证价格
|
|||
|
|
func (bv *BusinessValidator) ValidatePrice(price float64) error {
|
|||
|
|
if price < 0 {
|
|||
|
|
return fmt.Errorf("价格不能为负数")
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateStringLength 验证字符串长度
|
|||
|
|
func (bv *BusinessValidator) ValidateStringLength(str string, fieldName string, min, max int) error {
|
|||
|
|
length := len(strings.TrimSpace(str))
|
|||
|
|
if min > 0 && length < min {
|
|||
|
|
return fmt.Errorf("%s长度不能少于%d位", fieldName, min)
|
|||
|
|
}
|
|||
|
|
if max > 0 && length > max {
|
|||
|
|
return fmt.Errorf("%s长度不能超过%d位", fieldName, max)
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateRequired 验证必填字段
|
|||
|
|
func (bv *BusinessValidator) ValidateRequired(value interface{}, fieldName string) error {
|
|||
|
|
if value == nil {
|
|||
|
|
return fmt.Errorf("%s不能为空", fieldName)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
switch v := value.(type) {
|
|||
|
|
case string:
|
|||
|
|
if strings.TrimSpace(v) == "" {
|
|||
|
|
return fmt.Errorf("%s不能为空", fieldName)
|
|||
|
|
}
|
|||
|
|
case *string:
|
|||
|
|
if v == nil || strings.TrimSpace(*v) == "" {
|
|||
|
|
return fmt.Errorf("%s不能为空", fieldName)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateRange 验证数值范围
|
|||
|
|
func (bv *BusinessValidator) ValidateRange(value float64, fieldName string, min, max float64) error {
|
|||
|
|
if value < min {
|
|||
|
|
return fmt.Errorf("%s不能小于%v", fieldName, min)
|
|||
|
|
}
|
|||
|
|
if value > max {
|
|||
|
|
return fmt.Errorf("%s不能大于%v", fieldName, max)
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateSliceNotEmpty 验证切片不为空
|
|||
|
|
func (bv *BusinessValidator) ValidateSliceNotEmpty(slice interface{}, fieldName string) error {
|
|||
|
|
if slice == nil {
|
|||
|
|
return fmt.Errorf("%s不能为空", fieldName)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
switch v := slice.(type) {
|
|||
|
|
case []string:
|
|||
|
|
if len(v) == 0 {
|
|||
|
|
return fmt.Errorf("%s不能为空", fieldName)
|
|||
|
|
}
|
|||
|
|
case []int:
|
|||
|
|
if len(v) == 0 {
|
|||
|
|
return fmt.Errorf("%s不能为空", fieldName)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|