package validator import ( "fmt" "net/url" "regexp" "strconv" "strings" "time" "github.com/go-playground/validator/v10" ) // RegisterCustomValidators 注册所有自定义验证器 func RegisterCustomValidators(validate *validator.Validate) { // 手机号验证器 validate.RegisterValidation("phone", validatePhone) // 用户名验证器(字母开头,允许字母数字下划线,3-20位) validate.RegisterValidation("username", validateUsername) // 强密码验证器(至少8位,包含大小写字母和数字) validate.RegisterValidation("strong_password", validateStrongPassword) // 统一社会信用代码验证器 validate.RegisterValidation("social_credit_code", validateSocialCreditCode) // 身份证号验证器 validate.RegisterValidation("id_card", validateIDCard) // 价格验证器(非负数) validate.RegisterValidation("price", validatePrice) // 排序方向验证器 validate.RegisterValidation("sort_order", validateSortOrder) // 产品代码验证器(字母数字下划线连字符,3-50位) validate.RegisterValidation("product_code", validateProductCode) // UUID验证器 validate.RegisterValidation("uuid", validateUUID) // URL验证器 validate.RegisterValidation("url", validateURL) // 企业邮箱验证器 validate.RegisterValidation("enterprise_email", validateEnterpriseEmail) // 企业地址验证器 validate.RegisterValidation("enterprise_address", validateEnterpriseAddress) // IP地址验证器 validate.RegisterValidation("ip", validateIP) // 授权日期验证器 validate.RegisterValidation("auth_date", validateAuthDate) } // validatePhone 手机号验证 func validatePhone(fl validator.FieldLevel) bool { phone := fl.Field().String() matched, _ := regexp.MatchString(`^1[3-9]\d{9}$`, phone) return matched } // validateUsername 用户名验证 func validateUsername(fl validator.FieldLevel) bool { username := fl.Field().String() matched, _ := regexp.MatchString(`^[a-zA-Z][a-zA-Z0-9_]{2,19}$`, username) return matched } // validateStrongPassword 强密码验证 func validateStrongPassword(fl validator.FieldLevel) bool { password := fl.Field().String() if len(password) < 8 { return false } hasUpper := regexp.MustCompile(`[A-Z]`).MatchString(password) hasLower := regexp.MustCompile(`[a-z]`).MatchString(password) hasDigit := regexp.MustCompile(`\d`).MatchString(password) return hasUpper && hasLower && hasDigit } // validateSocialCreditCode 统一社会信用代码验证 func validateSocialCreditCode(fl validator.FieldLevel) bool { code := fl.Field().String() matched, _ := regexp.MatchString(`^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$`, code) return matched } // validateIDCard 身份证号验证 func validateIDCard(fl validator.FieldLevel) bool { idCard := fl.Field().String() 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) return matched } // validatePrice 价格验证 func validatePrice(fl validator.FieldLevel) bool { price := fl.Field().Float() return price >= 0 } // validateSortOrder 排序方向验证 func validateSortOrder(fl validator.FieldLevel) bool { sortOrder := fl.Field().String() return sortOrder == "" || sortOrder == "asc" || sortOrder == "desc" } // validateProductCode 产品代码验证 func validateProductCode(fl validator.FieldLevel) bool { code := fl.Field().String() matched, _ := regexp.MatchString(`^[a-zA-Z0-9_-]{3,50}$`, code) return matched } // validateUUID UUID验证 func validateUUID(fl validator.FieldLevel) bool { uuid := fl.Field().String() matched, _ := regexp.MatchString(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, uuid) return matched } // validateURL URL验证 func validateURL(fl validator.FieldLevel) bool { urlStr := fl.Field().String() _, err := url.ParseRequestURI(urlStr) return err == nil } // validateEnterpriseEmail 企业邮箱验证 func validateEnterpriseEmail(fl validator.FieldLevel) bool { email := fl.Field().String() // 邮箱格式验证:用户名@域名.顶级域名 matched, _ := regexp.MatchString(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`, email) return matched } // validateEnterpriseAddress 企业地址验证 func validateEnterpriseAddress(fl validator.FieldLevel) bool { address := fl.Field().String() // 地址长度验证:2-200字符,不能只包含空格 if len(strings.TrimSpace(address)) < 2 || len(address) > 200 { return false } // 地址不能只包含特殊字符 matched, _ := regexp.MatchString(`^[^\s]+.*[^\s]+$`, strings.TrimSpace(address)) return matched } // validateIP IP地址验证(支持IPv4) func validateIP(fl validator.FieldLevel) bool { ip := fl.Field().String() // 使用正则表达式验证IPv4格式 pattern := `^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$` matched, _ := regexp.MatchString(pattern, ip) return matched } // validateAuthDate 授权日期验证器 // 格式:YYYYMMDD-YYYYMMDD,之前的日期范围必须包括今天 func validateAuthDate(fl validator.FieldLevel) bool { authDate := fl.Field().String() if authDate == "" { return true // 空值由required标签处理 } // 检查格式:YYYYMMDD-YYYYMMDD parts := strings.Split(authDate, "-") if len(parts) != 2 { return false } startDateStr := parts[0] endDateStr := parts[1] // 检查日期格式是否为8位数字 if len(startDateStr) != 8 || len(endDateStr) != 8 { return false } // 解析开始日期 startDate, err := parseYYYYMMDD(startDateStr) if err != nil { return false } // 解析结束日期 endDate, err := parseYYYYMMDD(endDateStr) if err != nil { return false } // 检查开始日期不能晚于结束日期 if startDate.After(endDate) { return false } // 获取今天的日期(去掉时间部分) today := time.Now().Truncate(24 * time.Hour) // 检查日期范围是否包括今天 // 如果两个日期都是今天也行 return !startDate.After(today) && !endDate.Before(today) } // parseYYYYMMDD 解析YYYYMMDD格式的日期字符串 func parseYYYYMMDD(dateStr string) (time.Time, error) { if len(dateStr) != 8 { return time.Time{}, fmt.Errorf("日期格式错误") } year, err := strconv.Atoi(dateStr[:4]) if err != nil { return time.Time{}, err } month, err := strconv.Atoi(dateStr[4:6]) if err != nil { return time.Time{}, err } day, err := strconv.Atoi(dateStr[6:8]) if err != nil { return time.Time{}, err } // 验证日期有效性 date := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) // 检查解析后的日期是否与输入一致(防止无效日期如20230230) expectedDateStr := date.Format("20060102") if expectedDateStr != dateStr { return time.Time{}, fmt.Errorf("无效日期") } return date, nil }