mirror of
https://github.com/unti-io/go-utils.git
synced 2025-09-27 12:42:24 +08:00
413 lines
9.6 KiB
Go
413 lines
9.6 KiB
Go
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
|
||
}
|