MVC查询数据接收及校验

本来想写一篇aspx的TreeView控件绑值的文章的,在写案例的时候,写了一半,发现有些地方还得考虑以下,就留待下次了。

这一篇的话,是最近在开发一个项目的时候,有大量的页面和数据表,需要花式查询,

后台接收前台传递过来的数据的时候,被虐的欲仙欲死,大量的校验和重复代码,

后来找到了一种非常不错的方法,分享出来,下面是正文。。。。。

 

使用过MVC的人都知道,它有一个非常方便的功能,就是自动绑值,先来一个最简单的:

1         public ActionResult Index(string userName, int type) {
2             /*
3              代码块
4              */
5             return View();
6         }    

当从前台传递过来的数据中,有两个参数名字为userName或type时,MVC会自动帮我们将参数类型转好,值给好。

我们要做的无非是直接使用罢了,但是,当要传递的值非常多的时候,无论是写还是看,都会非常吃力,比如这样:

1         public ActionResult Index01(string userName, int type, string code, int height, string sex, DateTime startTime, DateTime endTime) {
2             /*
3              代码块
4              */
5             return View();
6         }

其实,七个查询参数并不多,当参数数量达到十个,二十个时,相信我,你会炸的,

一般这个时候,我们可用选择使用对象,就像这样:

 1         public ActionResult Index01(User user) {
 2             /*
 3              代码块
 4              */
 5             return View();
 6         }
 7 
 8     /// <summary>
 9     /// 用户类
10     /// </summary>
11     public class User {
12 
13         /// <summary>
14         /// 用户姓名
15         /// </summary>
16         public string userName;
17 
18         /// <summary>
19         /// 用户类型
20         /// </summary>
21         public int type;
22 
23         /// <summary>
24         /// 身份证号
25         /// </summary>
26         public string code;
27 
28         /// <summary>
29         /// 用户身高
30         /// </summary>
31         public int height;
32 
33         /// <summary>
34         /// 用户性别
35         /// </summary>
36         public string sex;
37 
38         #region 注册时间范围
39 
40         public DateTime startTime;
41         public DateTime endTime;
42 
43         #endregion
44 
45     }

这样写是不是看起来舒服了很多?MVC同样能够帮你将数据依次绑好,同时,代码的复用率也会提高很多,

现在解决了数据接收的问题,接下来的,就是数据的校验了。

==========分隔符==========

拿到参数后,我们是不能立刻去使用的,需要对参数进行一次校验,校验的目的,就是防止有人恶意传递错误数据给后台,

若不进行数据校验的话,很容易导致项目崩溃,或者数据丢失等等一系列问题,简单的说一些校验类型吧,

string 变量,主要校验是否包含sql注入字符,然后判断是否为null,还要去掉多余的空格

int 变量,主要检验是否在某一个范围内,以及默认值是0还是-1,或者是其它的一些数字

DateTime 变量,一般都是两个一起使用,一个开始一个结束,这个时候我们就要校验,开始时间是否小于或等于结束时间,以及结束时间是否小于或等于当前时间,

还有一点值得注意的是,若开始时间和结束时间精确到天时,若是同一天,在数据库是无法查出数据的,所以必须精确到秒

 

我们按这个思路去添加校验:

        public ActionResult Index01(User user) {

            // 字符串校验
            // 判断是否为空为null
            if (string.IsNullOrEmpty(user.userName))
                user.userName = user.userName.Trim();// 去掉多余空格
            // SQL注入校验
            if (CheckSQL(user.userName))
                user.userName = "";// 替换掉带有SQL注入的字符

            // 数字校验
            if (user.type < 0 || 20 < user.type)
                user.type = 0;// 当范围不在[0,20]时,给默认值0

            // 时间校验
            /*
              没有六七十行搞不定,就不写了,,,
             */

            return View();
        }

看起来还是不错的,但如果考虑到,每个数据的范围不一样,校验也是各不相同,而且,一个数据校验最少就得写两行代码,

当参数多了的时候,光校验代码都得写上一两百行,可以想想,如果有一百个类似的页面,呵呵。。。

不仅仅是看的难受,维护也是相当困难的,

所以我就想,能不能前台向后台请求的数据,都用一个类来接收,所有的校验都写在这个类里面,

类的每个参数,在输出的时候,都进行校验,这样可用极大的省略,接收数据之后在视图中的校验,而是将校验放在一起,

同时,相同校验方法的的参数,可用限制参数名为同一个,代码的复用率也会得到提升,对于维护和修改也能轻松进行,,,

 

说干就干,当时写出来的类,经过这么久的修改和添加,已经可以拿出来溜溜了,先上使用代码吧:

 1         public ActionResult Index01(ReqData data) {
 2 
 3             string sqlstr = string.Format(" select * from dt_user where userName='{0}' ", data.UserName);
 4 
 5             /*
 6              执行sql语句,以及其他操作,,,
 7              */
 8 
 9             return View();
10         }

有没有瞬间感觉画风不对,说好的校验哪去了?怎么能直接使用??

其实,所有的校验都在ReqData这个类里面,可以在它里面添加自己需要的参数,以及对应的校验方法,这样,使用的时候就会非常简单了

我主要想要分享的是一种封装的思想和技巧,可能ReqData这个类还是很简陋,但还是希望能对大家有所帮助,好像有点长,贴上代码先:

 

  1 using System;
  2 
  3 namespace Demo.Model {
  4 
  5     /// <summary>
  6     /// 用于接收前台传过来的数据
  7     /// </summary>
  8     public struct ReqData {
  9 
 10         #region 分页数据
 11 
 12         /// <summary>
 13         /// 数据总行数
 14         /// </summary>
 15         public int PageCount { get; set; }
 16 
 17         /// <summary>
 18         /// 当前页码
 19         /// </summary>
 20         public int PageIndex {
 21             get {
 22                 if (pageIndex == 0)
 23                     pageIndex = 1;
 24                 return pageIndex;
 25             }
 26             set {
 27                 pageIndex = value;
 28             }
 29         }
 30         private int pageIndex;
 31 
 32         /// <summary>
 33         /// 每页行数
 34         /// </summary>
 35         public int PageSize {
 36             get {
 37                 if (pageSize == 0)
 38                     pageSize = 10;
 39                 return pageSize;
 40             }
 41             set {
 42                 pageSize = value;
 43             }
 44         }
 45         private int pageSize;
 46 
 47         /// <summary>
 48         /// 页面跳转链接,带参数
 49         /// 用于分页跳转
 50         /// </summary>
 51         public string PageUrl { get; set; }
 52 
 53         /// <summary>
 54         /// 页面跳转链接,不带参数
 55         /// 用于删除时跳转
 56         /// </summary>
 57         public string GetPageUrl {
 58             get {
 59                 // 判断是否为空
 60                 if (PageUrl == null)
 61                     return "";
 62 
 63                 // 检测是否有参数
 64                 int index = PageUrl.LastIndexOf("?");
 65                 // 去掉参数
 66                 if (index > 0)
 67                     return PageUrl.Substring(0, index);
 68                 return PageUrl;
 69             }
 70         }
 71 
 72         #endregion
 73 
 74         #region 页面参数
 75 
 76         /// <summary>
 77         /// 视图样式,{ txt:列表视图,img:图片视图 }
 78         /// </summary>
 79         public string Show {
 80             get {
 81                 CheckStr(ref show);
 82 
 83                 if (string.IsNullOrEmpty(show))
 84                     show = "txt";
 85                 if (show != "txt" && show != "img")
 86                     show = "txt";
 87                 return show;
 88             }
 89             set { show = value; }
 90         }
 91         private string show;
 92 
 93         /// <summary>
 94         /// 导航栏标题
 95         /// </summary>
 96         public string Title {
 97             get { return CheckStr(ref title); }
 98             set { title = value; }
 99         }
100         private string title;
101 
102         #endregion
103 
104         #region 查询参数
105 
106         /// <summary>
107         /// 用户编号
108         /// </summary>
109         public int? ID {
110             get { return id; }
111             set { id = value; }
112         }
113         private int? id;
114 
115         /// <summary>
116         /// 用户名
117         /// </summary>  
118         public string UserName {
119             get { return CheckStr(ref userName); }
120             set { userName = value; }
121         }
122         private string userName;
123 
124         /// <summary>
125         /// 用户等级,范围:[0,3]
126         /// </summary>
127         public int? Leavel {
128             get { return GetNumInMinToMax(ref leavel, 0, 3); }
129             set { leavel = value; }
130         }
131         private int? leavel;
132         
133         #region 时间参数
134 
135         #region 时间接收
136         
137         private DateTime? start_Time;
138         /// <summary>
139         /// 开始时间,时分秒为 0:0:0,并且不能大于End_Time
140         /// </summary>
141         public DateTime? Start_Time {
142             get {
143                 // 允许开始时间为空
144                 if (start_Time == null)
145                     return start_Time;
146 
147                 // 若开始时间大于当前时间
148                 if (start_Time.Value > DateTime.Now)
149                     // 开始时间为当前时间
150                     start_Time = DateTime.Now;
151 
152                 // 当结束时间不为空
153                 if (end_Time != null)
154                     // 当开始时间大于结束时间时
155                     if (start_Time > End_Time)
156                         // 取结束时间当天的凌晨
157                         start_Time = new DateTime(End_Time.Value.Year, End_Time.Value.Month, End_Time.Value.Day, 0, 0, 0);
158 
159                 return start_Time;
160             }
161             set { start_Time = value; }
162         }
163 
164         private DateTime? end_Time;
165         /// <summary>
166         /// 结束时间,时分秒为 23:59:59,并且不能大于当前时间
167         /// </summary>
168         public DateTime? End_Time {
169             get {
170                 // 允许结束时间为空
171                 if (end_Time == null)
172                     return end_Time;
173 
174                 // 若结束时间大于当前时间
175                 if (end_Time.Value >= DateTime.Now)
176                     // 结束时间为当前时间
177                     end_Time = DateTime.Now;
178                 else {
179                     // 获取结束时间的信息
180                     int year = end_Time.Value.Year;
181                     int month = end_Time.Value.Month;
182                     int day = end_Time.Value.Day;
183 
184                     int hour = end_Time.Value.Hour;
185                     int minute = end_Time.Value.Minute;
186                     int second = end_Time.Value.Second;
187 
188                     // 当时分秒均为0时,为结束时间加上时分秒
189                     if (hour == 0 && minute == 0 && second == 0) {
190                         DateTime now = DateTime.Now;
191                         // 若结束时间的年月日正好是当天
192                         if (now.Year == year && now.Month == month && now.Day == day)
193                             end_Time = now;
194                         // 否则,给到结束时间那天,最后一秒
195                         else
196                             end_Time = new DateTime(year, month, day, 23, 59, 59);
197                     }
198                 }
199 
200                 return end_Time;
201             }
202             set { end_Time = value; }
203         }
204 
205         #endregion
206 
207         #region 时间输出
208 
209         /// <summary>
210         /// 时间字符串返回格式
211         /// 若不设置,默认为"yyyy-MM-dd HH:mm:ss"
212         /// </summary>
213         public string Format {
214             get {
215                 if (format == null)
216                     format = "yyyy-MM-dd HH:mm:ss";
217                 return format;
218             }
219             set { format = value; }
220         }
221         private string format;
222 
223         /// <summary>
224         /// 用于返回开始时间字符串
225         /// </summary>
226         public string GetStarTimeStr {
227             get {
228                 if (Start_Time.HasValue)
229                     return Start_Time.Value.ToString(Format);
230                 return "";
231             }
232         }
233 
234         /// <summary>
235         /// 用于返回结束时间字符串
236         /// </summary>
237         public string GetEndTimeStr {
238             get {
239                 if (End_Time.HasValue)
240                     return End_Time.Value.ToString(Format);
241                 return "";
242             }
243         }
244 
245         #endregion
246 
247         #endregion
248 
249         #endregion
250 
251         #region 校验方法
252 
253         /// <summary>
254         /// 保证num的值范围为,[min,max]
255         /// </summary>
256         /// <param name="num">原始数据</param>
257         /// <param name="min">最小值</param>
258         /// <param name="max">最大值</param>
259         /// <param name="def">默认值(不填时,默认值为最小值)</param>
260         /// <returns></returns>
261         public int? GetNumInMinToMax(ref int? num, int min, int max, int? def = null) {
262             // 若def没有值,将最小值给它
263             if (!def.HasValue)
264                 def = min;
265             // 若num没有值,将默认值给它
266             if (!num.HasValue)
267                 num = def;
268             // 若num的值小于最小值,或大于最大值,将默认值给它
269             else if (num < min || max < num)
270                 num = def;
271 
272             return num;
273         }
274 
275         /// <summary>
276         /// 将字符串去掉空格,并进行敏感字符检测
277         /// </summary>
278         /// <param name="str">原字符串</param>
279         /// <param name="Ischeck">是否开启敏感字符校验</param>
280         /// <param name="def">默认的值,字符串为空时,赋此值</param>
281         /// <returns></returns>
282         public string CheckStr(ref string str, bool Ischeck = true,string def="") {
283             if (string.IsNullOrEmpty(str))
284                 return str = def;
285             str = str.Trim();
286             if (Ischeck)
287                 if (!GetIsFormText(str))
288                     str = "请不要输入敏感字符!";
289             return str;
290         }
291 
292         /// <summary>
293         /// 检测是否含有危险字符(防止Sql注入)
294         /// 转自:http://blog.csdn.net/chaozi/article/details/4462312
295         /// </summary>
296         /// <param name="contents">预检测的内容</param>
297         /// <returns>返回True或false</returns>
298         public static bool GetIsFormText(string contents) {
299             bool bReturnValue = false;
300             if (contents.Length > 0) {
301                 //convert to lower
302                 string sLowerStr = contents.ToLower();
303                 //RegularExpressions
304                 string sRxStr = "(/sand/s)|(/sand/s)|(/slike/s)|(select/s)|(insert/s)|" +
305                     "(delete/s)|(update/s[/s/S].*/sset)|(create/s)|(/stable)|(<[iframe|/iframe|" +
306                     "script|/script])|(')|(/sexec)|(/sdeclare)|(/struncate)|(/smaster)|(/sbackup)|(/smid)|(/scount)";
307                 //Match
308                 bool bIsMatch = false;
309                 System.Text.RegularExpressions.Regex sRx = new
310 
311                 System.Text.RegularExpressions.Regex(sRxStr);
312                 bIsMatch = sRx.IsMatch(sLowerStr, 0);
313                 if (bIsMatch) {
314                     bReturnValue = true;
315                 }
316             }
317             return bReturnValue;
318         }
319 
320         #endregion
321 
322         #region 数据绑定方法
323 
324         /// <summary>
325         /// 返回指定区间的日期,默认今天
326         /// </summary>
327         /// <param name="dateSection"></param>
328         public void GetDateSection(DateSection dateSection = DateSection.Today) {
329 
330             // 判断枚举中,是否存在此项
331             if (!Enum.IsDefined(typeof(DateSection), (int)dateSection))
332                 dateSection = DateSection.Today;
333 
334             // 日期
335             DateTime Date = DateTime.Now;
336 
337             // 倒退的天数
338             int BackDay = 0;
339 
340             switch (dateSection) {
341 
342                 #region =====今天=====
343 
344                 case DateSection.Today:
345                     End_Time = Date;
346                     Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, 0, 0, 0, 0);
347                     break;
348 
349                 #endregion
350 
351                 #region =====昨天=====
352 
353                 case DateSection.Yesterday:
354                     Date = DateTime.Now.AddDays(-1);
355 
356                     End_Time = new DateTime(Date.Year, Date.Month, Date.Day, 23, 59, 59, 999);
357                     Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, 0, 0, 0, 0, 0);
358                     break;
359 
360                 #endregion
361 
362                 #region =====本周=====
363 
364                 case DateSection.ThisWeek:
365                     End_Time = Date;
366 
367                     // 获取今天是本周第几天
368                     BackDay = Convert.ToInt32(Date.DayOfWeek.ToString("d"));
369 
370                     Date = DateTime.Now.AddDays(-BackDay);
371                     Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, 0, 0, 0, 0);
372                     break;
373 
374                 #endregion
375 
376                 #region =====上周=====
377 
378                 case DateSection.LastWeek:
379                     BackDay = Convert.ToInt32(Date.DayOfWeek.ToString("d")) + 1;
380 
381                     // 到上周最后一天
382                     Date = DateTime.Now.AddDays(-BackDay);
383                     End_Time = new DateTime(Date.Year, Date.Month, Date.Day, 23, 59, 59, 999);
384 
385                     // 到上周第一天
386                     Date = Date.AddDays(-6);
387                     Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, 0, 0, 0, 0);
388 
389                     break;
390 
391                 #endregion
392 
393                 #region =====本月=====
394 
395                 case DateSection.ThisMonth:
396                     End_Time = Date;
397                     Start_Time = new DateTime(Date.Year, Date.Month, 1, 0, 0, 0, 0);
398                     break;
399 
400                 #endregion
401 
402                 #region =====上月=====
403 
404                 case DateSection.LastMonth:
405 
406                     BackDay = Date.Day;
407 
408                     // 到上月最后一天
409                     Date = DateTime.Now.AddDays(-BackDay);
410                     End_Time = new DateTime(Date.Year, Date.Month, Date.Day, 23, 59, 59, 999);
411 
412                     Start_Time = new DateTime(Date.Year, Date.Month, 1, 0, 0, 0, 0);
413                     break;
414 
415                 #endregion
416 
417                 #region =====今年=====
418 
419                 case DateSection.ThisYear:
420                     End_Time = Date;
421                     Start_Time = new DateTime(Date.Year, 1, 1, 0, 0, 0, 0);
422                     break;
423 
424                 #endregion
425 
426                 #region =====去年=====
427 
428                 case DateSection.LastYear:
429                     BackDay = Date.DayOfYear;
430 
431                     // 到去年最后一天
432                     Date = DateTime.Now.AddDays(-BackDay);
433                     End_Time = new DateTime(Date.Year, Date.Month, Date.Day, 23, 59, 59, 999);
434 
435                     Start_Time = new DateTime(Date.Year, 1, 1, 0, 0, 0, 0);
436                     break;
437 
438                 #endregion
439 
440                 default: break;
441             }
442 
443         }
444 
445         /// <summary>
446         /// 保证开始和结束时间绝对不为空
447         /// </summary>
448         /// <param name="DateLong">间隔长度,默认:7</param>
449         /// <param name="dateFormat">间隔单位,默认:Day(天)</param>
450         public void GetDateNow(int DateLong = 7, DateFormat dateFormat = DateFormat.Day) {
451 
452             // 校验是否存在此枚举
453             if (Enum.IsDefined(typeof(DateFormat), (int)dateFormat))
454                 dateFormat = DateFormat.Day;
455 
456             // 初始化结束时间
457             if (End_Time == null)
458                 End_Time = DateTime.Now;
459 
460             DateTime? star;
461 
462             // 有校验的时间
463             star = new DateTime();
464             star = Start_Time;
465             ChangStar(ref star, End_Time, DateLong, dateFormat);
466             Start_Time = star;
467 
468         }
469 
470         /// <summary>
471         /// 根据结束时间,修改开始时间
472         /// 若开始时间有值,则不改动
473         /// </summary>
474         /// <param name="Start">开始时间</param>
475         /// <param name="End">结束时间</param>
476         /// <param name="DateLong">间隔长度</param>
477         /// <param name="dateFormat">间隔单位</param>
478         private void ChangStar(ref DateTime? Start, DateTime? End, int DateLong, DateFormat dateFormat) {
479 
480             if (Start.HasValue)
481                 return;
482 
483             DateLong = 0 - DateLong;
484 
485             // 获取开始时间
486             switch (dateFormat) {
487                 // 年份
488                 case DateFormat.Year:
489                     Start = End.Value.AddYears(DateLong);
490                     break;
491                 // 月份
492                 case DateFormat.Month:
493                     Start = End.Value.AddMonths(DateLong);
494                     break;
495                 // 天数
496                 case DateFormat.Day:
497                     Start = End.Value.AddDays(DateLong);
498                     break;
499                 // 小时
500                 case DateFormat.Hour:
501                     Start = End.Value.AddHours(DateLong);
502                     break;
503                 // 分钟
504                 case DateFormat.Minute:
505                     Start = End.Value.AddMinutes(DateLong);
506                     break;
507                 // 秒钟
508                 case DateFormat.Second:
509                     Start = End.Value.AddSeconds(DateLong);
510                     break;
511             }
512 
513         }
514 
515         #endregion
516     }
517 
518     /// <summary>
519     /// 时间格式
520     /// </summary>
521     public enum DateFormat {
522         /// <summary>
523         /// 年份
524         /// </summary>
525         Year,
526         /// <summary>
527         /// 月份
528         /// </summary>
529         Month,
530         /// <summary>
531         /// 天数
532         /// </summary>
533         Day,
534         /// <summary>
535         /// 小时
536         /// </summary>
537         Hour,
538         /// <summary>
539         /// 分钟
540         /// </summary>
541         Minute,
542         /// <summary>
543         /// 秒钟
544         /// </summary>
545         Second
546     }
547 
548     /// <summary>
549     /// 时间区间
550     /// </summary>
551     public enum DateSection {
552         /// <summary>
553         /// 今天
554         /// </summary>
555         Today,
556         /// <summary>
557         /// 昨天
558         /// </summary>
559         Yesterday,
560         /// <summary>
561         /// 本周,星期天为第一天
562         /// </summary>
563         ThisWeek,
564         /// <summary>
565         /// 上周,星期天为第一天
566         /// </summary>
567         LastWeek,
568         /// <summary>
569         /// 本月
570         /// </summary>
571         ThisMonth,
572         /// <summary>
573         /// 上月
574         /// </summary>
575         LastMonth,
576         /// <summary>
577         /// 今年
578         /// </summary>
579         ThisYear,
580         /// <summary>
581         /// 去年
582         /// </summary>
583         LastYear
584     }
585 
586 }
View Code

 

个人觉着,虽然代码一般般,但里面有不少小技巧还是很不错的,适合那些比我还新的新手学习一下,比如时间校验,,那个真的是伤透了心

如果大家发现了有什么bug,欢迎指出,或者有比较有趣的点子也欢迎互相交流,,,嗯,就酱紫,我去纠结TreeView控件绑值的问题,,

 

posted @ 2017-09-24 17:19  步尘  阅读(1239)  评论(0编辑  收藏  举报