参数声明式校验

Posted 初冬十月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了参数声明式校验相关的知识,希望对你有一定的参考价值。

 

用户输入都是不可信的,我想,大多数后端开发人员,都有这么一个共识。

然后,在写每一个方法的时候,基本都会有一坨if校验,我也不例外。

代码写多了,有时候就会想,能不能优化下,能不能优雅点?

于是,我又开始寻寻觅觅...
这个,就是,声明式验证...

以下是我整理的代码:

 

声明式验证核心部分:

技术分享
1     public enum ValidateType
2     {
3         IsString = 10000,
4         IsInt32 = 20000,
5         IsDecimal = 30000,
6         IsDateTime = 40000,
7         IsBoolean = 50000,
8     }
View Code
技术分享
  1     [AttributeUsage(AttributeTargets.All)]
  2     public class ValidateAttribute : Attribute
  3     {
  4         //是否必填
  5         private bool isRequired = true;
  6         //最小长度
  7         private int minLength = 0;
  8         //最大长度
  9         private int maxLength = Int32.MaxValue;
 10         //字段指定长度
 11         private int stringLength = Int32.MaxValue;
 12         //验证类型
 13         private ValidateType validateType;
 14 
 15         /// <summary>
 16         /// 显示名称
 17         /// </summary>
 18         public string DisplayName { get; set; }
 19 
 20         /// <summary>
 21         /// 是否必填
 22         /// </summary>
 23         public bool IsRequired
 24         {
 25             get
 26             {
 27                 return isRequired;
 28             }
 29             set
 30             {
 31                 isRequired = value;
 32             }
 33         }
 34 
 35         /// <summary>
 36         /// 最小长度
 37         /// </summary>
 38         public int MinLength
 39         {
 40             get
 41             {
 42                 return minLength;
 43             }
 44             set
 45             {
 46                 minLength = value;
 47             }
 48         }
 49 
 50         /// <summary>
 51         /// 最大长度
 52         /// </summary>
 53         public int MaxLength
 54         {
 55             get
 56             {
 57                 return maxLength;
 58             }
 59             set
 60             {
 61                 maxLength = value;
 62             }
 63         }
 64 
 65         /// <summary>
 66         /// 字段指定长度
 67         /// </summary>
 68         public int StringLength
 69         {
 70             get
 71             {
 72                 return stringLength;
 73             }
 74             set
 75             {
 76                 stringLength = value;
 77             }
 78         }
 79 
 80         /// <summary>
 81         /// 正则表达式校验格式
 82         /// </summary>
 83         public string RegexpCheckFormat { get; set; }
 84 
 85         /// <summary>
 86         /// 正则表达式显示格式
 87         /// </summary>
 88         public string RegexpDisplayFormat { get; set; }
 89 
 90         /// <summary>
 91         /// Int32集合
 92         /// </summary>
 93         public int[] Int32Collection { get; set; }
 94 
 95         /// <summary>
 96         /// 字符串集合
 97         /// </summary>
 98         public string[] StringCollection { get; set; }
 99 
100         /// <summary>
101         /// 验证类型
102         /// </summary>
103         public ValidateType ValidateType
104         {
105             get
106             {
107                 return validateType;
108             }
109             set
110             {
111                 validateType = value;
112             }
113         }
114 
115         /// <summary>
116         /// 构造函数
117         /// </summary>
118         /// <param name="validateType"></param>
119         public ValidateAttribute(ValidateType validateType)
120         {
121             this.validateType = validateType;
122         }
123     }
View Code
技术分享
  1     public static class ValidateHandler
  2     {
  3         /// <summary>
  4         /// 获得结果
  5         /// </summary>
  6         /// <param name="instance">类对象实例</param>
  7         /// <returns></returns>
  8         public static string GetResultString(object instance)
  9         {
 10             var result = string.Empty;
 11             if (instance.IsNull())
 12             {
 13                 return "instance 参数不能为空";
 14             }
 15             Type type = instance.GetType();
 16             PropertyInfo[] properties = type.GetProperties();
 17             foreach (PropertyInfo property in properties)
 18             {
 19                 //获取验证特性
 20                 object[] validAttrs = property.GetCustomAttributes(typeof(ValidateAttribute), true);
 21                 if (!validAttrs.IsNull())
 22                 {
 23                     //获取属性的值
 24                     object propVal = property.GetValue(instance, null);
 25                     //属性值长度
 26                     int propValLength = 0;
 27                     foreach (ValidateAttribute validAttr in validAttrs)
 28                     {
 29                         //获取属性名称
 30                         var propName = !validAttr.DisplayName.IsNullOrEmptyOrWhiteSpace() ? validAttr.DisplayName : property.Name;
 31                         //校验是否必填
 32                         if (validAttr.IsRequired)
 33                         {
 34                             if (propVal.IsNull())
 35                             {
 36                                 return "{0} 字段是必需的".FormatWith(propName);
 37                             }
 38                             if (validAttr.ValidateType == ValidateType.IsString
 39                                 && propVal.ToString().IsNullOrEmptyOrWhiteSpace())
 40                             {
 41                                 return "{0} 字段是必需的".FormatWith(propName);
 42                             }
 43                             if (validAttr.ValidateType == ValidateType.IsInt32
 44                                 && !propVal.IsInt32())
 45                             {
 46                                 return "{0} 字段不是Int32类型".FormatWith(propName);
 47                             }
 48                             if (validAttr.ValidateType == ValidateType.IsDecimal
 49                                 && !propVal.IsDecimal())
 50                             {
 51                                 return "{0} 字段不是Decimal类型".FormatWith(propName);
 52                             }
 53                             if (validAttr.ValidateType == ValidateType.IsDateTime)
 54                             {
 55                                 if (!propVal.IsDateTime())
 56                                 {
 57                                     return "{0} 字段不是日期类型".FormatWith(propName);
 58                                 }
 59                                 if (propVal.ToDateTime() == DateTime.MinValue)
 60                                 {
 61                                     return "{0} 字段是必需的".FormatWith(propName);
 62                                 }
 63                             }
 64                             if (validAttr.ValidateType == ValidateType.IsBoolean
 65                                 && !propVal.IsBoolean())
 66                             {
 67                                 return "{0} 字段不是布尔类型".FormatWith(propName);
 68                             }
 69                         }
 70                         propValLength = propVal.IsNull() ? 0 : propVal.ToString().Length;
 71                         //校验最小长度
 72                         if (propValLength < validAttr.MinLength)
 73                         {
 74                             return "{0} 字段或数组长度不能小于{1}".FormatWith(propName, validAttr.MinLength);
 75                         }
 76                         //校验最大长度
 77                         if (propValLength > validAttr.MaxLength)
 78                         {
 79                             return "{0} 字段或数组长度不能大于{1}".FormatWith(propName, validAttr.MaxLength);
 80                         }
 81                         if (validAttr.StringLength != Int32.MaxValue
 82                             && propValLength != validAttr.StringLength)
 83                         {
 84                             return "{0} 字段长度错误,长度必须为{1}".FormatWith(propName, validAttr.StringLength);
 85                         }
 86                         //校验正则表达式
 87                         if (!validAttr.RegexpCheckFormat.IsNullOrEmptyOrWhiteSpace())
 88                         {
 89                             if (!Regex.IsMatch(propVal.ToString(), validAttr.RegexpCheckFormat))
 90                             {
 91                                 if (!validAttr.RegexpDisplayFormat.IsNull())
 92                                 {
 93                                     return "{0} 字段格式错误,正确格式为{1}".FormatWith(propName, validAttr.RegexpDisplayFormat);
 94                                 }
 95                                 else
 96                                 {
 97                                     return "{0} 字段格式错误".FormatWith(propName);
 98                                 }
 99                             }
100                         }
101                         //校验集合
102                         if (propVal.IsInt32()
103                             && !validAttr.Int32Collection.IsNull()
104                             && !validAttr.Int32Collection.Contains(propVal.ToInt32()))
105                         {
106                             return "{0} 字段必须为 {1} 中的一个".FormatWith(propName, string.Join(",", validAttr.Int32Collection));
107                         }
108                         if (!validAttr.StringCollection.IsNull()
109                             && !validAttr.StringCollection.Contains(propVal.ToString()))
110                         {
111                             return "{0} 字段必须为 {1} 中的一个".FormatWith(propName, string.Join(",", validAttr.Int32Collection));
112                         }
113                     }
114                 }
115             }
116             return string.Empty;
117         }
118     }
View Code

 

demo:

有一个需要验证的资源类:

技术分享
 1     public class ResourceDto
 2     {
 3         [Validate(ValidateType.IsDateTime, IsRequired = false)]
 4         public string ResoCreateTime { get; set; }
 5 
 6         [Validate(ValidateType.IsString, IsRequired = false)]
 7         public string ResoDesc { get; set; }
 8 
 9         [Validate(ValidateType.IsString, IsRequired = false)]
10         public string ResoId { get; set; }
11 
12         [Validate(ValidateType.IsBoolean, DisplayName = "是否显示")]
13         public string ResoIsShow { get; set; }
14 
15         [Validate(ValidateType.IsString, DisplayName = "资源名称")]
16         public string ResoName { get; set; }
17 
18         [Validate(ValidateType.IsInt32, DisplayName = "资源排序")]
19         public string ResoOrder { get; set; }
20 
21         [Validate(ValidateType.IsString, DisplayName = "父资源ID")]
22         public string ResoParentId { get; set; }
23 
24         [Validate(ValidateType.IsString, DisplayName = "资源类型")]
25         public string ResoType { get; set; }
26 
27         [Validate(ValidateType.IsDateTime, IsRequired = false)]
28         public string ResoUpdateTime { get; set; }
29 
30         [Validate(ValidateType.IsString, IsRequired = false)]
31         public string ResoUrl { get; set; }
32     }
View Code

 

控制器保存数据校验部分:

技术分享
1                 ResourceDto model = new javascriptSerializer().Deserialize<ResourceDto>("FormData".ValueOfForm());
2 
3                 var checkResult = ValidateHandler.GetResultString(model);
4                 if (checkResult != string.Empty)
5                 {
6                     //以下是处理错误的代码
7                     return;
8                 }
View Code

 

使用声明式验证,代码有没有简洁美观点?哈哈。

 










以上是关于参数声明式校验的主要内容,如果未能解决你的问题,请参考以下文章

Spring MVC学习—Validation基于注解的声明式数据校验机制全解一万字

spring注解式参数校验

使用 Spring Validation 优雅地进行参数校验

Android Fragment 在布局中声明,如何设置参数?

布局中声明的Android Fragment,如何设置参数?

将React函数式组件作为函数的参数传递时,我应该如何用TS声明函数参数类型