Files
go-utils/utils/validate.go
陈兔子 eaaac7b20a v1.7.0
2025-09-12 02:33:18 +08:00

413 lines
9.6 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 utils
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"
"github.com/spf13/cast"
)
type validator struct {
model any
message map[string]string
rule func(name string, value any, rule string, message map[string]string) error
}
// Validate - 验证器入口
var Validate = func(model any) *validator {
return &validator{
model: model,
rule: ValidateRules,
}
}
// Validate - 验证模型
func (this *validator) Validate(model any) *validator {
this.model = model
return this
}
// Message - 自定义错误信息
func (this *validator) Message(message map[string]string) *validator {
this.message = message
return this
}
// Rule - 自定义校验规则
func (this *validator) Rule(callback func(name string, value any, rule string, message map[string]string) error) *validator {
this.rule = callback
return this
}
// Check - 验证
func (this *validator) Check(params any) (err error) {
if this.model == nil {
return errors.New("model is nil")
}
// params 转 string
data, _ := json.Marshal(params)
// string 转 map
var tempMap map[string]any
err = json.Unmarshal(data, &tempMap)
if err != nil {
return err
}
// 获取结构体的字段和标签
for i := 0; i < reflect.TypeOf(this.model).NumField(); i++ {
field := reflect.TypeOf(this.model).Field(i)
tag := field.Tag
rule := tag.Get("rule")
// 字段名
var name string
// 字段值
var value any
if !Is.Empty(cast.ToString(tag.Get("json"))) {
name = tag.Get("json")
} else {
name = field.Name
}
value = tempMap[name]
if Is.Empty(rule) {
// 结束本次循环,进入下一次循环
continue
}
err := this.rule(name, value, rule, this.message)
if err != nil {
return err
}
}
return nil
}
// ValidateRules - 验证规则
/**
* @rule - 内置规则 - 如下:
* required必填
* min最小值
* max最大值
* email是否为邮箱
* number是否为数字
* float是否为浮点数
* bool是否为布尔值
* slice是否为切片 - (数组)
* jsonStr是否为 JSON 字符串
* accepted验证某个字段是否为为 yes, on, 或是 1
* date是否为日期
* alpha只能包含字母
* alphaNum只能包含字母和数字
* alphaDash只能包含字母、数字和下划线_及破折号-
* chs只能包含汉字
* chsAlpha只能包含汉字、字母
* chsAlphaNum只能包含汉字、字母和数字
* chsDash只能是汉字、字母、数字和下划线_及破折号-
* cntrl是否为控制字符 - (换行、缩进、空格)
* graph是否为可见字符 - (除空格外的所有可打印字符)
* lower是否为小写字母
* upper是否为大写字母
* space是否为空白字符 - (空格、制表符、换页符等)
* xdigit是否为十六进制字符 - 0-9、a-f、A-F
* activeUrl是否为有效的域名或者IP
* url是否为有效的URL地址
* ip是否为IP地址
* mobile是否为手机号
* idCard是否为身份证号
* MacAddr是否为MAC地址
* zip是否为邮政编码
**/
func ValidateRules(name string, value any, rule string, message map[string]string) (err error) {
// 获取 rule 中的规则 - 字符串切片,逗号分隔
rules := strings.Split(rule, ",")
// 判断 rules 是否包含 required
if !InArray("required", cast.ToStringSlice(rules)) {
// 判断 value 是否为空
if Is.Empty(value) {
// 结束本次循环,进入下一次循环
return nil
}
}
for _, val := range rules {
if strings.Contains(val, "=") {
// 获取规则和参数
ruleAndParam := strings.Split(val, "=")
first := ruleAndParam[0]
second := ruleAndParam[1]
switch first {
case "min":
// 判断长度是否小于最小值
if second != "" && len(cast.ToString(value)) < cast.ToInt(second) {
msg := message[name+"."+first]
if msg == "" {
msg = name + " length cannot be less than " + second + ""
}
return fmt.Errorf(msg)
}
case "max":
// 判断长度是否大于最大值
if second != "" && len(cast.ToString(value)) > cast.ToInt(second) {
msg := message[name+"."+first]
if msg == "" {
msg = name + " length cannot be greater than " + second + ""
}
return fmt.Errorf(msg)
}
}
} else {
switch val {
case "required":
if Is.Empty(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " is not empty!"
}
return fmt.Errorf(msg)
}
case "email":
if !Is.Email(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect! Required in <email> format!"
}
return fmt.Errorf(msg)
}
case "number":
if !Is.Number(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect! Required in <number> format!"
}
return fmt.Errorf(msg)
}
case "float":
if !Is.Float(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect! Required in <float> format!"
}
return fmt.Errorf(msg)
}
case "bool":
if !Is.Bool(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect! Required in <bool> format!"
}
return fmt.Errorf(msg)
}
case "slice":
if !Is.Slice(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect! Required in <array> format!"
}
return fmt.Errorf(msg)
}
case "jsonStr":
if !Is.JsonString(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect! Required in <json string> format!"
}
return fmt.Errorf(msg)
}
case "accepted":
if !Is.Accepted(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "date":
if !Is.Date(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect! Required in <date> format!"
}
return fmt.Errorf(msg)
}
case "alpha":
if !Is.Alpha(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "alphaNum":
if !Is.AlphaNum(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "alphaDash":
if !Is.AlphaDash(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "chs":
if !Is.Chs(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "chsAlpha":
if !Is.ChsAlpha(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "chsAlphaNum":
if !Is.ChsAlphaNum(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "chsDash":
if !Is.ChsDash(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "cntrl":
if !Is.Cntrl(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "graph":
if !Is.Graph(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "lower":
if !Is.Lower(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "upper":
if !Is.Upper(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "space":
if !Is.Space(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "xdigit":
if !Is.Xdigit(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "activeUrl":
if !Is.ActiveUrl(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "url":
if !Is.Url(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "ip":
if !Is.Ip(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "mobile":
if !Is.Mobile(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "idCard":
if !Is.IdCard(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "MacAddr":
if !Is.MacAddr(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
case "zip":
if !Is.Zip(value) {
msg := message[name+"."+val]
if msg == "" {
msg = name + " format is incorrect!"
}
return fmt.Errorf(msg)
}
}
}
}
return nil
}