tianyuan-api-server/apps/api/internal/validator/validator.go

225 lines
6.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package validator
import (
"encoding/json"
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"time"
"github.com/go-playground/validator/v10"
)
var validate *validator.Validate
// 初始化自定义校验器
func init() {
validate = validator.New()
if err := validate.RegisterValidation("validName", validName); err != nil {
panic(fmt.Sprintf("注册 validName 验证器时发生错误: %v", err))
}
// 注册自定义验证器 validMobileNo
if err := validate.RegisterValidation("validMobileNo", validMobileNo); err != nil {
panic(fmt.Sprintf("注册 validMobileNo 验证器时发生错误: %v", err))
}
// 注册自定义验证器 validDate
if err := validate.RegisterValidation("validDate", validDate); err != nil {
panic(fmt.Sprintf("注册 validDate 验证器时发生错误: %v", err))
}
// 注册自定义验证器 validIDCard
if err := validate.RegisterValidation("validIDCard", validIDCard); err != nil {
panic(fmt.Sprintf("注册 validIDCard 验证器时发生错误: %v", err))
}
// 注册自定义验证器 validTimeRange
if err := validate.RegisterValidation("validTimeRange", validTimeRange); err != nil {
panic(fmt.Sprintf("注册 validTimeRange 验证器时发生错误: %v", err))
}
if err := validate.RegisterValidation("validBankCard", validBankCard); err != nil {
panic(fmt.Sprintf("注册 validBankCard 验证器时发生错误: %v", err))
}
if err := validate.RegisterValidation("validUSCI", validUSCI); err != nil {
panic(fmt.Sprintf("注册 validUSCI 验证器时发生错误: %v", err))
}
if err := validate.RegisterValidation("validMobileType", validMobileType); err != nil {
panic(fmt.Sprintf("注册 validMobileType 验证器时发生错误: %v", err))
}
// 注册自定义验证器 validAuthDate
if err := validate.RegisterValidation("validAuthDate", validAuthDate); err != nil {
panic(fmt.Sprintf("注册 validAuthDate 验证器时发生错误: %v", err))
}
}
// ValidateAndParse 封装了解密、解析和校验逻辑
func ValidateAndParse(decryptData []byte, req interface{}) error {
// 解析解密后的 JSON 数据
if err := json.Unmarshal(decryptData, req); err != nil {
return errors.New("解密后的数据格式不正确")
}
// 校验
v := GetValidator()
if err := v.Struct(req); err != nil {
for _, validationErr := range err.(validator.ValidationErrors) {
field := validationErr.StructField()
tag := validationErr.Tag()
return errors.New(GetErrorMessage(field, tag))
}
}
// 如果没有错误,返回 nil
return nil
}
func ValidateAuthDate(date string) error {
// 校验日期格式是否为 yyyyMMdd-yyyyMMdd
validDateRangePattern := `^\d{4}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])-\d{4}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$`
matched, _ := regexp.MatchString(validDateRangePattern, date)
if !matched {
return errors.New("日期范围格式错误应为yyyyMMdd-yyyyMMdd")
}
// 分割开始和结束日期
parts := strings.Split(date, "-")
if len(parts) != 2 {
return errors.New("日期范围格式错误应为yyyyMMdd-yyyyMMdd")
}
startDateStr, endDateStr := parts[0], parts[1]
// 解析开始日期
startDate, err := time.Parse("20060102", startDateStr)
if err != nil {
return errors.New("开始日期格式错误")
}
// 解析结束日期
endDate, err := time.Parse("20060102", endDateStr)
if err != nil {
return errors.New("结束日期格式错误")
}
// 校验开始日期不大于结束日期
if startDate.After(endDate) {
return errors.New("开始日期不能大于结束日期")
}
// 校验时间范围不能超过5年
maxDuration := 5 * 365 * 24 * time.Hour // 5年的近似时间不考虑闰年
if endDate.Sub(startDate) > maxDuration {
return errors.New("时间范围不能超过5年")
}
// 校验当前时间在范围内
now := time.Now()
if now.Before(startDate) || now.After(endDate) {
return errors.New("当前时间必须在指定的时间范围内")
}
return nil
}
// 获取验证器实例
func GetValidator() *validator.Validate {
return validate
}
// 自定义的名称验证
func validName(fl validator.FieldLevel) bool {
name := fl.Field().String()
validNamePattern := `^[\p{Han}]+$`
matched, _ := regexp.MatchString(validNamePattern, name)
return matched
}
// 自定义的手机号验证
func validMobileNo(fl validator.FieldLevel) bool {
phone := fl.Field().String()
validMobileNoPattern := `^1[3-9]\d{9}$`
matched, _ := regexp.MatchString(validMobileNoPattern, phone)
return matched
}
// 自定义正则表达式校验 yyyyMMdd 格式
func validDate(fl validator.FieldLevel) bool {
date := fl.Field().String()
validDatePattern := `^\d{4}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$`
matched, _ := regexp.MatchString(validDatePattern, date)
return matched
}
// 自定义身份证校验
func validIDCard(fl validator.FieldLevel) bool {
id := fl.Field().String()
validIDPattern := `^\d{17}(\d|X|x)$` // 匹配18位身份证号码
matched, _ := regexp.MatchString(validIDPattern, id)
return matched
}
// 自定义 time_range 校验 (1-5年)
func validTimeRange(fl validator.FieldLevel) bool {
timeRange := fl.Field().String()
if timeRange == "" {
return true // 如果为空,认为是有效的,因为是非必填项
}
value, err := strconv.Atoi(timeRange)
if err != nil || value < 1 || value > 5 {
return false
}
return true
}
func validBankCard(fl validator.FieldLevel) bool {
bankCard := fl.Field().String()
// 银行卡号一般是13到19位的数字
validBankCardPattern := `^\d{13,19}$`
matched, _ := regexp.MatchString(validBankCardPattern, bankCard)
return matched
}
func validUSCI(fl validator.FieldLevel) bool {
usci := fl.Field().String()
// 社会信用代码为18位数字和大写字母的组合最后一位为校验码
validUSCIPattern := `^[1-9A-Z]{2}[0-9]{6}[0-9A-Z]{9}[0-9A-Z]$`
matched, _ := regexp.MatchString(validUSCIPattern, usci)
return matched
}
// 自定义的手机号类型验证(可以为空)
func validMobileType(fl validator.FieldLevel) bool {
mobileType := fl.Field().String()
if mobileType == "" {
return true // 如果为空,认为是有效的
}
// 校验是否是 CTCC, CMCC, CUCC 之一
validTypes := map[string]bool{
"CTCC": true, // 中国电信
"CMCC": true, // 中国移动
"CUCC": true, // 中国联通
}
return validTypes[mobileType]
}
// 自定义的日期范围验证器(用于结构体字段验证)
func validAuthDate(fl validator.FieldLevel) bool {
dateRange := fl.Field().String()
// 如果是空字符串,认为是有效的(非必填项)
if dateRange == "" {
return true
}
err := ValidateAuthDate(dateRange)
return err == nil
}