package check import ( "fmt" "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" zhTranslations "github.com/go-playground/validator/v10/translations/zh" "github.com/pkg/errors" "strings" "time" ) const ( timeNotZeroTag = "timenotzero" ) var validate = validator.New(validator.WithRequiredStructEnabled()) var translator ut.Translator func init() { validate.SetTagName("check") zhLocale := zh.New() zhTranslator := ut.New(zhLocale) trans, _ := zhTranslator.GetTranslator("zh") err := zhTranslations.RegisterDefaultTranslations(validate, trans) if err != nil { panic(err) } translator = trans registerCustomTags() } func registerCustomTags() { if err := validate.RegisterValidation(timeNotZeroTag, func(fl validator.FieldLevel) bool { fieldValue := fl.Field() if !fieldValue.IsValid() { return true } switch value := fieldValue.Interface().(type) { case time.Time: return !value.IsZero() case *time.Time: if value != nil { return true } return !value.IsZero() default: return false } }); err != nil { fmt.Println(err) return } } func Struct(obj any, fieldNameMap map[string]string) Result { return newResult(validate.Struct(obj), nil, fieldNameMap) } type Result struct { err error translatedErrs map[string]string fieldNameMap map[string]string } func newResult(err error, translatedErrs map[string]string, fieldNameMap map[string]string) Result { return Result{ err: err, translatedErrs: translatedErrs, fieldNameMap: fieldNameMap, } } func (result Result) IsError() bool { return result.err != nil } func (result Result) CheckFields(fieldNames ...string) error { if len(fieldNames) == 0 { return nil } return result.checkFields(fieldNames...) } func (result Result) CheckStruct() error { return result.checkStruct() } func (result Result) checkFields(fieldNames ...string) error { if result.err == nil { return nil } translatedResult := result.translation() if translatedResult.translatedErrs == nil || len(translatedResult.translatedErrs) == 0 { return translatedResult.err } errMsg := strings.Builder{} for _, fieldName := range fieldNames { for errStructFieldName, translatedErr := range translatedResult.translatedErrs { errStructFieldNameParts := strings.Split(errStructFieldName, ".") errFieldName := errStructFieldNameParts[len(errStructFieldNameParts)-1] if fieldName == errFieldName { if translatedResult.fieldNameMap != nil { fieldCNName, ok := translatedResult.fieldNameMap[fieldName] if ok { translatedErr = strings.ReplaceAll(translatedErr, fieldName, fieldCNName) } } errMsg.WriteString(translatedErr + "\n") } } } if errMsg.Len() > 0 { return errors.New(errMsg.String()) } return nil } func (result Result) checkStruct() error { if result.err == nil { return nil } translatedResult := result.translation() if translatedResult.translatedErrs == nil || len(translatedResult.translatedErrs) == 0 { return translatedResult.err } errMsg := strings.Builder{} for errStructFieldName, translatedErr := range translatedResult.translatedErrs { if translatedResult.fieldNameMap != nil { errStructFieldNameParts := strings.Split(errStructFieldName, ".") errFieldName := errStructFieldNameParts[len(errStructFieldNameParts)-1] fieldCNName, ok := translatedResult.fieldNameMap[errFieldName] if ok { translatedErr = strings.ReplaceAll(translatedErr, errFieldName, fieldCNName) } } errMsg.WriteString(translatedErr + "\n") } if errMsg.Len() > 0 { return errors.New(errMsg.String()) } return nil } func (result Result) translation() Result { if result.err == nil { return result } if result.translatedErrs != nil { return result } var validationErrors validator.ValidationErrors if !errors.As(result.err, &validationErrors) { return result } translatedErrors := validationErrors.Translate(translator) for _, validationError := range validationErrors { if validationError.Tag() == timeNotZeroTag { translatedErrors[validationError.Field()] = validationError.Field() + "使用了时间零值" } } return newResult(result.err, translatedErrors, result.fieldNameMap) }