-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvalidator.go
758 lines (724 loc) · 24.1 KB
/
validator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
// Package validator 实现了一个支持场景/国际化/自定义错误/自定义验证规则的 map[string]interface{} 元素批量验证器,意在支持各种框架的 model 层实现自动验证,亦可单独使用,
// 该验证器是逻辑验证器(float64(10)/int32(10)/"10" 均可被 intValidator 验证通过)而不是强类型验证器
// 考虑到经过 encoding/json 解析后的数字类型均被解析为 float64,强类型验证器不太可用,故此设计
// 如果需要强类型验证,可以使用 AddValidator 自行扩展,或直接断言
package validator
import (
"errors"
"fmt"
"github.com/goindow/validator/i18n"
"net"
"reflect"
"regexp"
"strconv"
"strings"
"unicode/utf8"
// "github.com/goindow/toolbox"
)
const (
DEFAULT_LANG = "ZH_CN"
PATTERN_ZIPCODE = `^[1-9]\d{5}$`
PATTERN_TEL = `^(0\d{2,3}(\-)?)?\d{7,8}$`
PATTERN_MOBILE = `^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][01356789]|[4][579]))\d{8}$`
PATTERN_EMAIL = `^[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[a-zA-Z0-9](?:[\w-]*[\w])?$`
)
// 验证规则
type Rule struct {
// 必须,待验证属性,单个属性 string,多个属性 []string,其他类型或未定义将 panic
Attr interface{}
// 必须,验证规则,即验证器,不存在的验证器或未定义将 panic
Rule string
// 可选,自定义错误信息
Message string
// 可选,可空限制,作用于除 requiredValidator 外的所有验证器
// false(默认) - 有值验证/无值跳过(如果同时设置了 requiredValidator ,则报 required 错误,此时错误是由 requiredValidator 报出的)
// true - 有值验证/无值报 required 错误
Required bool
// 可选,符号限制,作用于 numberValidator、integerValidator、decimalValidator
// 0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
Symbol int64
// 可选,最大限制,作用于 stringValidator、numberValidator、integerValidator、decimalValidator
// Max < Min 将 Panic
// 作用于 stringValidator、integerValidator 只能是整数,其他将 panic
// 作用于 numberValidator、decimalValidator 只能是整数或浮点数,其他将 panic
Max interface{}
// 可选,最小限制,同 Rule.Max
Min interface{}
// 必选(inValidator),枚举限制,作用于 inValidator
Enum []string
// 必选(regexValidator),正则匹配模式,作用于 regexValidator
Pattern string
// 必选(fucValidator),自定义验证函数,作用于 funcValidator
Func F
}
// 场景
type Scence string
// 验证规则集 - 单个场景
type ScenceRules []Rule
// 验证规则集 - 所有场景
type Rules map[Scence]ScenceRules
type M map[string]interface{}
// 验证错误类型
type E map[string]string
// 验证器函数类型
type F func(string, Rule, M) E
type validator struct {
// 默认语言
lang string
// 默认错误
default_errors map[string]string
// 验证器
validators map[string]F
// 错误收信息
errors []E
}
// New 构造器,validator.New()
func New() *validator {
this := &validator{
lang: DEFAULT_LANG,
default_errors: i18n.Errors[DEFAULT_LANG],
}
// 挂载内置验证器
this.mount()
return this
}
// Lang 设置默认的错误信息语言
func (this *validator) Lang(lang string) *validator {
l := strings.ToUpper(lang)
if _, ok := i18n.Errors[l]; !ok {
panic(lang + " unsupport language")
}
this.lang = l
this.default_errors = i18n.Errors[l]
return this
}
// AddValidator 自定义验证器
func (this *validator) AddValidator(name string, customValidator F) {
if _, ok := this.validators[name]; ok {
panic(errors.New("validator named '" + name + "' already exists"))
}
this.validators[name] = customValidator
}
// Validate 场景验证
func (this *validator) Validate(rules Rules, obj M, scence Scence) []E {
// 初始化 errors
this.errors = make([]E, 0)
// 场景不存在
scenceRules, ok := rules[scence]
if !ok {
panic(fmt.Sprint(scence) + " scence undefined")
}
// 验证
for _, rule := range scenceRules {
this.dispatch(rule, obj)
}
return this.errors
}
// dispatch 验证调度器
func (this *validator) dispatch(rule Rule, obj M) {
name := rule.Rule
// Rule.Rule 未定义
if name == "" {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Rule' not found"))
}
// 验证器不存在
f, ok := this.validators[name]
if !ok {
panic(errors.New(name + " validator undefined"))
}
// Rule.Attr 类型错误
attr := rule.Attr
switch attr.(type) {
case string:
this.adapter(f, rule, obj, false)
case []string:
this.adapter(f, rule, obj, true)
case nil:
panic(errors.New(fmt.Sprint(rule) + " attribute 'Attr' not found"))
default:
panic("attribute 'Attr' should be 'string' or '[]string'")
}
}
// adapter 多字段适配器
func (this *validator) adapter(f F, rule Rule, obj M, ismultiple bool) {
// 多字段
if ismultiple {
for _, attr := range rule.Attr.([]string) {
this.validate(f, attr, rule, obj)
}
return
}
// 单字段
this.validate(f, rule.Attr.(string), rule, obj)
}
// validate 验证
func (this *validator) validate(f F, attr string, rule Rule, obj M) {
if e := f(attr, rule, obj); e != nil {
this.errors = append(this.errors, e)
}
}
// generator 错误信息生成器
func (this *validator) generator(name string, attr string, rule Rule, placeholder ...interface{}) E {
ok := false
e := rule.Message
// 自定义错误信息
if e != "" {
return E{attr: e}
}
// 内置错误信息
e, ok = this.default_errors[name]
if ok {
// 替换标签,已删除
// e = strings.Replace(e, "{label}", attr, -1)
// 替换占位符
e = fmt.Sprintf(e, placeholder...)
} else { // 内置错误信息不存在
e = "unknow error"
}
return E{attr: e}
}
// mount 挂载内置验证器
func (this *validator) mount() {
this.validators = map[string]F{
"func": this.funcValidator, // 自定义验证函数
"required": this.requiredValidator,
"in": this.inValidator,
"string": this.stringValidator,
"integer": this.integerValidator,
"decimal": this.decimalValidator,
"number": this.numberValidator,
"boolean": this.booleanValidator,
"ip": this.ipValidator,
"regex": this.regexValidator,
"email": this.emailValidator,
"tel": this.telValidator,
"mobile": this.mobileValidator,
"zipcode": this.zipcodeValidator,
// 别名
"int": this.integerValidator, // integer
"float": this.decimalValidator, // decimal
"bool": this.booleanValidator, // boolean
}
}
// funcValidator 自定义验证函数
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// Rule.Func F 必须 使用 Rule.Func 来验证本条 Rule
func (this *validator) funcValidator(attr string, rule Rule, obj M) E {
f := rule.Func
if f == nil {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Func' not found or empty"))
}
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
return f(attr, rule, obj)
}
// requiredValidator 必填
func (this *validator) requiredValidator(attr string, rule Rule, obj M) E {
if _, ok := obj[attr]; ok {
return nil
}
return this.generator("required", attr, rule)
}
// inValidator 枚举
// 支持类型 int64、int32、int16、int8、int、float64、float32、string、bool
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// Rule.Enum []string 必须 被验证字段必须在 Rule.Enum 中
func (this *validator) inValidator(attr string, rule Rule, obj M) E {
enum := rule.Enum
if len(enum) == 0 {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Enum' not found or empty"))
}
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 枚举检测
var field string
switch v := obj[attr].(type) {
case int64:
field = strconv.Itoa(int(v))
case int32:
field = strconv.Itoa(int(v))
case int16:
field = strconv.Itoa(int(v))
case int8:
field = strconv.Itoa(int(v))
case int:
field = strconv.Itoa(v)
case float64:
field = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
field = strconv.FormatFloat(float64(v), 'f', -1, 32)
case string:
field = v
case bool:
field = strconv.FormatBool(v)
default:
return this.generator("inValid", attr, rule)
}
in := false
for _, v := range enum {
if v == field {
in = true
break
}
}
if !in {
return this.generator("in", attr, rule, "["+strings.Join(enum, "、")+"]")
}
return nil
}
// stringValidator 字符串
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// Rule.Max int 可选 被验证字段长度不能大于 Rule.Max
// Rule.Min in 可选 被验证字段长度不能小于 Rule.Min
func (this *validator) stringValidator(attr string, rule Rule, obj M) E {
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 类型检测
if reflect.ValueOf(obj[attr]).Kind() != reflect.String {
return this.generator("string", attr, rule)
}
// 长度检测
max := rule.Max
min := rule.Min
if max != nil || min != nil {
// 逻辑错误
if max != nil && reflect.ValueOf(max).Kind() != reflect.Int {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should be int"))
}
if min != nil && reflect.ValueOf(min).Kind() != reflect.Int {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Min' should be int"))
}
if max != nil && min != nil && min.(int) > max.(int) {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should greater than 'Min'"))
}
// 比较
length := int(utf8.RuneCountInString(obj[attr].(string)))
if max != nil && min == nil && length > max.(int) { // only Max
return this.generator("stringLengthMax", attr, rule, max)
}
if min != nil && max == nil && length < min.(int) { // only Min
return this.generator("stringLengthMin", attr, rule, min)
}
if max != nil && min != nil && (length > max.(int) || length < min.(int)) { // both
if max != min {
return this.generator("stringLengthRange", attr, rule, min, max) // range
}
return this.generator("stringLengthEqual", attr, rule, max) // euqal
}
}
return nil
}
// intValidator 整数(整数/无小数位的浮点数/整数字符串)
// 支持类型 int64、int32、int16、int8、int、float64、float32、string
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// Rule.Symbol int64 可选 0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
// Rule.Max int 可选 被验证字段大小不能大于 Rule.Max
// Rule.Min int 可选 被验证字段大小不能小于 Rule.Min
func (this *validator) integerValidator(attr string, rule Rule, obj M) E {
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 类型检测
var field float64
switch v := obj[attr].(type) {
case int64:
field = float64(v)
case int32:
field = float64(v)
case int16:
field = float64(v)
case int8:
field = float64(v)
case int:
field = float64(v)
case float64:
if v-float64(int(v)) != 0 { // 带小数位
return this.generator("integer", attr, rule)
}
field = v
case float32:
if v-float32(int(v)) != 0 { // 带小数位
return this.generator("integer", attr, rule)
}
field = float64(v)
case string:
f, err := strconv.ParseFloat(v, 64)
if err != nil { // 不能转换为 float64
return this.generator("integer", attr, rule)
}
if f-float64(int(f)) != 0 { // 带小数位
return this.generator("integer", attr, rule)
}
field = f
default:
return this.generator("integer", attr, rule)
}
// 正负检测
symbol := rule.Symbol
if (symbol > 0 && field <= 0) || (symbol < 0 && field >= 0) {
if symbol > 0 {
return this.generator("integerPositive", attr, rule)
}
return this.generator("integerNegative", attr, rule)
}
// 大小检测
max := rule.Max
min := rule.Min
if max != nil || min != nil {
errPrefix := "integer"
// 逻辑错误
if max != nil && reflect.ValueOf(max).Kind() != reflect.Int {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should be int"))
}
if min != nil && reflect.ValueOf(min).Kind() != reflect.Int {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Min' should be int"))
}
if max != nil && min != nil && min.(int) > max.(int) {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should greater than 'Min'"))
}
if symbol > 0 {
errPrefix += "Positive"
if max != nil && max.(int) <= 0 { // 要求被检测属性是正数,而最大值被设置成负数,panic
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should greater than 0 when 'Symbal' = " + strconv.FormatInt(symbol, 10)))
}
}
if symbol < 0 {
errPrefix += "Negative"
if min != nil && min.(int) >= 0 { // 要求被检测属性是负数,而最小值被设置成正数,panic
panic(errors.New(fmt.Sprint(rule) + " attribute 'Min' should less than 0 when 'Symbal' = " + strconv.FormatInt(symbol, 10)))
}
}
// 比较
if max != nil && min == nil && field > (float64)(max.(int)) { // only Max
return this.generator(errPrefix+"Max", attr, rule, max)
}
if min != nil && max == nil && field < (float64)(min.(int)) { // only Min
return this.generator(errPrefix+"Min", attr, rule, min)
}
if max != nil && min != nil && (field > (float64)(max.(int)) || field < (float64)(min.(int))) { // both
if max != min { // range
return this.generator(errPrefix+"Range", attr, rule, min, max)
}
return this.generator("equal", attr, rule, max) // euqal
}
}
return nil
}
// decimalValidator 小数(有小数位的浮点数/有小数位的浮点数字符串)
// 支持类型 float64、float32、string
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// Rule.Symbol int64 可选 0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
// Rule.Max int|float64 可选 被验证字段大小不能大于 Rule.Max
// Rule.Min int|float64 可选 被验证字段大小不能小于 Rule.Min
func (this *validator) decimalValidator(attr string, rule Rule, obj M) E {
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 类型检测
var field float64
switch v := obj[attr].(type) {
case float64:
field = v
case float32:
field = float64(v)
case string:
f, err := strconv.ParseFloat(v, 64)
if err != nil { // 不能转换为 float64
return this.generator("decimal", attr, rule)
}
field = f
default:
return this.generator("decimal", attr, rule)
}
// 不带小数位
if field-float64(int(field)) == 0 {
return this.generator("decimal", attr, rule)
}
// 正负检测
symbol := rule.Symbol
if (symbol > 0 && field <= 0) || (symbol < 0 && field >= 0) {
if symbol > 0 {
return this.generator("decimalPositive", attr, rule)
}
return this.generator("decimalNegative", attr, rule)
}
// 大小检测
max := rule.Max
min := rule.Min
var fmax, fmin float64
if max != nil || min != nil {
errPrefix := "decimal"
// 逻辑错误
if max != nil {
switch v := max.(type) {
case float64:
fmax = v
case int:
fmax = float64(v)
default:
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should be int or float64"))
}
}
if min != nil {
switch v := min.(type) {
case float64:
fmin = v
case int:
fmin = float64(v)
default:
panic(errors.New(fmt.Sprint(rule) + " attribute 'Min' should be int or float64"))
}
}
if max != nil && min != nil && fmin > fmax {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should greater than 'Min'"))
}
if symbol > 0 {
errPrefix += "Positive"
if max != nil && fmax <= 0 { // 要求被检测属性是正数,而最大值被设置成负数,panic
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should greater than 0 when 'Symbal' = " + strconv.FormatInt(symbol, 10)))
}
}
if symbol < 0 {
errPrefix += "Negative"
if min != nil && fmin >= 0 { // 要求被检测属性是负数,而最小值被设置成正数,panic
panic(errors.New(fmt.Sprint(rule) + " attribute 'Min' should less than 0 when 'Symbal' = " + strconv.FormatInt(symbol, 10)))
}
}
// 比较
if max != nil && min == nil && field > fmax { // only Max
return this.generator(errPrefix+"Max", attr, rule, max)
}
if min != nil && max == nil && field < fmin { // only Min
return this.generator(errPrefix+"Min", attr, rule, min)
}
if max != nil && min != nil && (field > fmax || field < fmin) { // both
if max != min { // range
return this.generator(errPrefix+"Range", attr, rule, min, max)
}
return this.generator("equal", attr, rule, max) // euqal
}
}
return nil
}
// numberValidator 数字(整数/浮点数/数字字符串)
// 支持类型 int64、int32、int16、int8、int、float64、float32、string
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// Rule.Symbol int64 可选 0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
// Rule.Max int|float64 可选 被验证字段大小不能大于 Rule.Max
// Rule.Min int|float64 可选 被验证字段大小不能小于 Rule.Min
func (this *validator) numberValidator(attr string, rule Rule, obj M) E {
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 类型检测
var field float64
switch v := obj[attr].(type) {
case int64:
field = float64(v)
case int32:
field = float64(v)
case int16:
field = float64(v)
case int8:
field = float64(v)
case int:
field = float64(v)
case float64:
field = v
case float32:
field = float64(v)
case string:
f, err := strconv.ParseFloat(v, 64)
if err != nil { // 不能转换为 float64
return this.generator("number", attr, rule)
}
field = f
default:
return this.generator("number", attr, rule)
}
// 正负检测
symbol := rule.Symbol
if (symbol > 0 && field <= 0) || (symbol < 0 && field >= 0) {
if symbol > 0 {
return this.generator("numberPositive", attr, rule)
}
return this.generator("numberNegative", attr, rule)
}
// 大小检测
max := rule.Max
min := rule.Min
var fmax, fmin float64
if max != nil || min != nil {
errPrefix := "number"
// 逻辑错误
if max != nil {
switch v := max.(type) {
case float64:
fmax = v
case int:
fmax = float64(v)
default:
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should be int or float64"))
}
}
if min != nil {
switch v := min.(type) {
case float64:
fmin = v
case int:
fmin = float64(v)
default:
panic(errors.New(fmt.Sprint(rule) + " attribute 'Min' should be int or float64"))
}
}
if max != nil && min != nil && fmin > fmax {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should greater than 'Min'"))
}
if symbol > 0 {
errPrefix += "Positive"
if max != nil && fmax <= 0 { // 要求被检测属性是正数,而最大值被设置成负数,panic
panic(errors.New(fmt.Sprint(rule) + " attribute 'Max' should greater than 0 when 'Symbal' = " + strconv.FormatInt(symbol, 10)))
}
}
if symbol < 0 {
errPrefix += "Negative"
if min != nil && fmin >= 0 { // 要求被检测属性是负数,而最小值被设置成正数,panic
panic(errors.New(fmt.Sprint(rule) + " attribute 'Min' should less than 0 when 'Symbal' = " + strconv.FormatInt(symbol, 10)))
}
}
// 比较
if max != nil && min == nil && field > fmax { // only Max
return this.generator(errPrefix+"Max", attr, rule, max)
}
if min != nil && max == nil && field < fmin { // only Min
return this.generator(errPrefix+"Min", attr, rule, min)
}
if max != nil && min != nil && (field > fmax || field < fmin) { // both
if max != min { // range
return this.generator(errPrefix+"Range", attr, rule, min, max)
}
return this.generator("equal", attr, rule, max) // euqal
}
}
return nil
}
// boolValidator 布尔(布尔值/字符串表示的布尔值[1、0、t、f、true、false(忽略大小写)])
// 支持类型 bool、string
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
func (this *validator) booleanValidator(attr string, rule Rule, obj M) E {
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 类型检测
switch v := obj[attr].(type) {
case bool:
return nil
case string:
if _, err := strconv.ParseBool(strings.ToLower(v)); err != nil {
return this.generator("boolean", attr, rule)
}
default:
return this.generator("boolean", attr, rule)
}
return nil
}
// ipValidator ipv4/ipv6
func (this *validator) ipValidator(attr string, rule Rule, obj M) E {
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 字符串检测
if reflect.ValueOf(obj[attr]).Kind() != reflect.String {
return this.generator("string", attr, rule)
}
// ip 检测
if ip := net.ParseIP(obj[attr].(string)); ip == nil {
return this.generator("ip", attr, rule)
}
return nil
}
// regexValidator 正则
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// Rule.Pattern string 必选 正则模式字符串
func (this *validator) regexValidator(attr string, rule Rule, obj M) E {
pattern := rule.Pattern
if pattern == "" {
panic(errors.New(fmt.Sprint(rule) + " attribute 'Pattern' not found or empty"))
}
// 必填检测
if _, ok := obj[attr]; !ok {
if !rule.Required { // 允许为空
return nil
}
return this.generator("required", attr, rule)
}
// 字符串检测
if reflect.ValueOf(obj[attr]).Kind() != reflect.String {
return this.generator("string", attr, rule)
}
// 正则检测
regex := regexp.MustCompile(pattern)
if !regex.MatchString(obj[attr].(string)) {
return this.generator(rule.Rule, attr, rule)
}
return nil
}
// emailValidator 邮箱
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
func (this *validator) emailValidator(attr string, rule Rule, obj M) E {
rule.Pattern = PATTERN_EMAIL
return this.regexValidator(attr, rule, obj)
}
// mobileValidator 中国大陆座机号
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
func (this *validator) telValidator(attr string, rule Rule, obj M) E {
rule.Pattern = PATTERN_TEL
return this.regexValidator(attr, rule, obj)
}
// mobileValidator 中国大陆手机号
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
func (this *validator) mobileValidator(attr string, rule Rule, obj M) E {
rule.Pattern = PATTERN_MOBILE
return this.regexValidator(attr, rule, obj)
}
// mobileValidator 中国大陆邮编
// Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
func (this *validator) zipcodeValidator(attr string, rule Rule, obj M) E {
rule.Pattern = PATTERN_ZIPCODE
return this.regexValidator(attr, rule, obj)
}