MVC查询数据接收及校验
本来想写一篇aspx的TreeView控件绑值的文章的,在写案例的时候,写了一半,发现有些地方还得考虑以下,就留待下次了。
这一篇的话,是最近在开发一个项目的时候,有大量的页面和数据表,需要花式查询,
后台接收前台传递过来的数据的时候,被虐的欲仙欲死,大量的校验和重复代码,
后来找到了一种非常不错的方法,分享出来,下面是正文。。。。。
使用过MVC的人都知道,它有一个非常方便的功能,就是自动绑值,先来一个最简单的:
- public ActionResult Index(string userName, int type) {
- /*
- 代码块
- */
- return View();
- }
当从前台传递过来的数据中,有两个参数名字为userName或type时,MVC会自动帮我们将参数类型转好,值给好。
我们要做的无非是直接使用罢了,但是,当要传递的值非常多的时候,无论是写还是看,都会非常吃力,比如这样:
- public ActionResult Index01(string userName, int type, string code, int height, string sex, DateTime startTime, DateTime endTime) {
- /*
- 代码块
- */
- return View();
- }
其实,七个查询参数并不多,当参数数量达到十个,二十个时,相信我,你会炸的,
一般这个时候,我们可用选择使用对象,就像这样:
- public ActionResult Index01(User user) {
- /*
- 代码块
- */
- return View();
- }
- /// <summary>
- /// 用户类
- /// </summary>
- public class User {
- /// <summary>
- /// 用户姓名
- /// </summary>
- public string userName;
- /// <summary>
- /// 用户类型
- /// </summary>
- public int type;
- /// <summary>
- /// 身份证号
- /// </summary>
- public string code;
- /// <summary>
- /// 用户身高
- /// </summary>
- public int height;
- /// <summary>
- /// 用户性别
- /// </summary>
- public string sex;
- #region 注册时间范围
- public DateTime startTime;
- public DateTime endTime;
- #endregion
- }
这样写是不是看起来舒服了很多?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 < || < user.type)
- user.type = ;// 当范围不在[0,20]时,给默认值0
- // 时间校验
- /*
- 没有六七十行搞不定,就不写了,,,
- */
- return View();
- }
看起来还是不错的,但如果考虑到,每个数据的范围不一样,校验也是各不相同,而且,一个数据校验最少就得写两行代码,
当参数多了的时候,光校验代码都得写上一两百行,可以想想,如果有一百个类似的页面,呵呵。。。
不仅仅是看的难受,维护也是相当困难的,
所以我就想,能不能前台向后台请求的数据,都用一个类来接收,所有的校验都写在这个类里面,
类的每个参数,在输出的时候,都进行校验,这样可用极大的省略,接收数据之后在视图中的校验,而是将校验放在一起,
同时,相同校验方法的的参数,可用限制参数名为同一个,代码的复用率也会得到提升,对于维护和修改也能轻松进行,,,
说干就干,当时写出来的类,经过这么久的修改和添加,已经可以拿出来溜溜了,先上使用代码吧:
- public ActionResult Index01(ReqData data) {
- string sqlstr = string.Format(" select * from dt_user where userName='{0}' ", data.UserName);
- /*
- 执行sql语句,以及其他操作,,,
- */
- return View();
- }
有没有瞬间感觉画风不对,说好的校验哪去了?怎么能直接使用??
其实,所有的校验都在ReqData这个类里面,可以在它里面添加自己需要的参数,以及对应的校验方法,这样,使用的时候就会非常简单了
我主要想要分享的是一种封装的思想和技巧,可能ReqData这个类还是很简陋,但还是希望能对大家有所帮助,好像有点长,贴上代码先:
- using System;
- namespace Demo.Model {
- /// <summary>
- /// 用于接收前台传过来的数据
- /// </summary>
- public struct ReqData {
- #region 分页数据
- /// <summary>
- /// 数据总行数
- /// </summary>
- public int PageCount { get; set; }
- /// <summary>
- /// 当前页码
- /// </summary>
- public int PageIndex {
- get {
- if (pageIndex == )
- pageIndex = ;
- return pageIndex;
- }
- set {
- pageIndex = value;
- }
- }
- private int pageIndex;
- /// <summary>
- /// 每页行数
- /// </summary>
- public int PageSize {
- get {
- if (pageSize == )
- pageSize = ;
- return pageSize;
- }
- set {
- pageSize = value;
- }
- }
- private int pageSize;
- /// <summary>
- /// 页面跳转链接,带参数
- /// 用于分页跳转
- /// </summary>
- public string PageUrl { get; set; }
- /// <summary>
- /// 页面跳转链接,不带参数
- /// 用于删除时跳转
- /// </summary>
- public string GetPageUrl {
- get {
- // 判断是否为空
- if (PageUrl == null)
- return "";
- // 检测是否有参数
- int index = PageUrl.LastIndexOf("?");
- // 去掉参数
- if (index > )
- return PageUrl.Substring(, index);
- return PageUrl;
- }
- }
- #endregion
- #region 页面参数
- /// <summary>
- /// 视图样式,{ txt:列表视图,img:图片视图 }
- /// </summary>
- public string Show {
- get {
- CheckStr(ref show);
- if (string.IsNullOrEmpty(show))
- show = "txt";
- if (show != "txt" && show != "img")
- show = "txt";
- return show;
- }
- set { show = value; }
- }
- private string show;
- /// <summary>
- /// 导航栏标题
- /// </summary>
- public string Title {
- get { return CheckStr(ref title); }
- set { title = value; }
- }
- private string title;
- #endregion
- #region 查询参数
- /// <summary>
- /// 用户编号
- /// </summary>
- public int? ID {
- get { return id; }
- set { id = value; }
- }
- private int? id;
- /// <summary>
- /// 用户名
- /// </summary>
- public string UserName {
- get { return CheckStr(ref userName); }
- set { userName = value; }
- }
- private string userName;
- /// <summary>
- /// 用户等级,范围:[0,3]
- /// </summary>
- public int? Leavel {
- get { return GetNumInMinToMax(ref leavel, , ); }
- set { leavel = value; }
- }
- private int? leavel;
- #region 时间参数
- #region 时间接收
- private DateTime? start_Time;
- /// <summary>
- /// 开始时间,时分秒为 0:0:0,并且不能大于End_Time
- /// </summary>
- public DateTime? Start_Time {
- get {
- // 允许开始时间为空
- if (start_Time == null)
- return start_Time;
- // 若开始时间大于当前时间
- if (start_Time.Value > DateTime.Now)
- // 开始时间为当前时间
- start_Time = DateTime.Now;
- // 当结束时间不为空
- if (end_Time != null)
- // 当开始时间大于结束时间时
- if (start_Time > End_Time)
- // 取结束时间当天的凌晨
- start_Time = new DateTime(End_Time.Value.Year, End_Time.Value.Month, End_Time.Value.Day, , , );
- return start_Time;
- }
- set { start_Time = value; }
- }
- private DateTime? end_Time;
- /// <summary>
- /// 结束时间,时分秒为 23:59:59,并且不能大于当前时间
- /// </summary>
- public DateTime? End_Time {
- get {
- // 允许结束时间为空
- if (end_Time == null)
- return end_Time;
- // 若结束时间大于当前时间
- if (end_Time.Value >= DateTime.Now)
- // 结束时间为当前时间
- end_Time = DateTime.Now;
- else {
- // 获取结束时间的信息
- int year = end_Time.Value.Year;
- int month = end_Time.Value.Month;
- int day = end_Time.Value.Day;
- int hour = end_Time.Value.Hour;
- int minute = end_Time.Value.Minute;
- int second = end_Time.Value.Second;
- // 当时分秒均为0时,为结束时间加上时分秒
- if (hour == && minute == && second == ) {
- DateTime now = DateTime.Now;
- // 若结束时间的年月日正好是当天
- if (now.Year == year && now.Month == month && now.Day == day)
- end_Time = now;
- // 否则,给到结束时间那天,最后一秒
- else
- end_Time = new DateTime(year, month, day, , , );
- }
- }
- return end_Time;
- }
- set { end_Time = value; }
- }
- #endregion
- #region 时间输出
- /// <summary>
- /// 时间字符串返回格式
- /// 若不设置,默认为"yyyy-MM-dd HH:mm:ss"
- /// </summary>
- public string Format {
- get {
- if (format == null)
- format = "yyyy-MM-dd HH:mm:ss";
- return format;
- }
- set { format = value; }
- }
- private string format;
- /// <summary>
- /// 用于返回开始时间字符串
- /// </summary>
- public string GetStarTimeStr {
- get {
- if (Start_Time.HasValue)
- return Start_Time.Value.ToString(Format);
- return "";
- }
- }
- /// <summary>
- /// 用于返回结束时间字符串
- /// </summary>
- public string GetEndTimeStr {
- get {
- if (End_Time.HasValue)
- return End_Time.Value.ToString(Format);
- return "";
- }
- }
- #endregion
- #endregion
- #endregion
- #region 校验方法
- /// <summary>
- /// 保证num的值范围为,[min,max]
- /// </summary>
- /// <param name="num">原始数据</param>
- /// <param name="min">最小值</param>
- /// <param name="max">最大值</param>
- /// <param name="def">默认值(不填时,默认值为最小值)</param>
- /// <returns></returns>
- public int? GetNumInMinToMax(ref int? num, int min, int max, int? def = null) {
- // 若def没有值,将最小值给它
- if (!def.HasValue)
- def = min;
- // 若num没有值,将默认值给它
- if (!num.HasValue)
- num = def;
- // 若num的值小于最小值,或大于最大值,将默认值给它
- else if (num < min || max < num)
- num = def;
- return num;
- }
- /// <summary>
- /// 将字符串去掉空格,并进行敏感字符检测
- /// </summary>
- /// <param name="str">原字符串</param>
- /// <param name="Ischeck">是否开启敏感字符校验</param>
- /// <param name="def">默认的值,字符串为空时,赋此值</param>
- /// <returns></returns>
- public string CheckStr(ref string str, bool Ischeck = true,string def="") {
- if (string.IsNullOrEmpty(str))
- return str = def;
- str = str.Trim();
- if (Ischeck)
- if (!GetIsFormText(str))
- str = "请不要输入敏感字符!";
- return str;
- }
- /// <summary>
- /// 检测是否含有危险字符(防止Sql注入)
- /// 转自:http://blog.csdn.net/chaozi/article/details/4462312
- /// </summary>
- /// <param name="contents">预检测的内容</param>
- /// <returns>返回True或false</returns>
- public static bool GetIsFormText(string contents) {
- bool bReturnValue = false;
- if (contents.Length > ) {
- //convert to lower
- string sLowerStr = contents.ToLower();
- //RegularExpressions
- string sRxStr = "(/sand/s)|(/sand/s)|(/slike/s)|(select/s)|(insert/s)|" +
- "(delete/s)|(update/s[/s/S].*/sset)|(create/s)|(/stable)|(<[iframe|/iframe|" +
- "script|/script])|(')|(/sexec)|(/sdeclare)|(/struncate)|(/smaster)|(/sbackup)|(/smid)|(/scount)";
- //Match
- bool bIsMatch = false;
- System.Text.RegularExpressions.Regex sRx = new
- System.Text.RegularExpressions.Regex(sRxStr);
- bIsMatch = sRx.IsMatch(sLowerStr, );
- if (bIsMatch) {
- bReturnValue = true;
- }
- }
- return bReturnValue;
- }
- #endregion
- #region 数据绑定方法
- /// <summary>
- /// 返回指定区间的日期,默认今天
- /// </summary>
- /// <param name="dateSection"></param>
- public void GetDateSection(DateSection dateSection = DateSection.Today) {
- // 判断枚举中,是否存在此项
- if (!Enum.IsDefined(typeof(DateSection), (int)dateSection))
- dateSection = DateSection.Today;
- // 日期
- DateTime Date = DateTime.Now;
- // 倒退的天数
- int BackDay = ;
- switch (dateSection) {
- #region =====今天=====
- case DateSection.Today:
- End_Time = Date;
- Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , );
- break;
- #endregion
- #region =====昨天=====
- case DateSection.Yesterday:
- Date = DateTime.Now.AddDays(-);
- End_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , );
- Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , , );
- break;
- #endregion
- #region =====本周=====
- case DateSection.ThisWeek:
- End_Time = Date;
- // 获取今天是本周第几天
- BackDay = Convert.ToInt32(Date.DayOfWeek.ToString("d"));
- Date = DateTime.Now.AddDays(-BackDay);
- Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , );
- break;
- #endregion
- #region =====上周=====
- case DateSection.LastWeek:
- BackDay = Convert.ToInt32(Date.DayOfWeek.ToString("d")) + ;
- // 到上周最后一天
- Date = DateTime.Now.AddDays(-BackDay);
- End_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , );
- // 到上周第一天
- Date = Date.AddDays(-);
- Start_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , );
- break;
- #endregion
- #region =====本月=====
- case DateSection.ThisMonth:
- End_Time = Date;
- Start_Time = new DateTime(Date.Year, Date.Month, , , , , );
- break;
- #endregion
- #region =====上月=====
- case DateSection.LastMonth:
- BackDay = Date.Day;
- // 到上月最后一天
- Date = DateTime.Now.AddDays(-BackDay);
- End_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , );
- Start_Time = new DateTime(Date.Year, Date.Month, , , , , );
- break;
- #endregion
- #region =====今年=====
- case DateSection.ThisYear:
- End_Time = Date;
- Start_Time = new DateTime(Date.Year, , , , , , );
- break;
- #endregion
- #region =====去年=====
- case DateSection.LastYear:
- BackDay = Date.DayOfYear;
- // 到去年最后一天
- Date = DateTime.Now.AddDays(-BackDay);
- End_Time = new DateTime(Date.Year, Date.Month, Date.Day, , , , );
- Start_Time = new DateTime(Date.Year, , , , , , );
- break;
- #endregion
- default: break;
- }
- }
- /// <summary>
- /// 保证开始和结束时间绝对不为空
- /// </summary>
- /// <param name="DateLong">间隔长度,默认:7</param>
- /// <param name="dateFormat">间隔单位,默认:Day(天)</param>
- public void GetDateNow(int DateLong = , DateFormat dateFormat = DateFormat.Day) {
- // 校验是否存在此枚举
- if (Enum.IsDefined(typeof(DateFormat), (int)dateFormat))
- dateFormat = DateFormat.Day;
- // 初始化结束时间
- if (End_Time == null)
- End_Time = DateTime.Now;
- DateTime? star;
- // 有校验的时间
- star = new DateTime();
- star = Start_Time;
- ChangStar(ref star, End_Time, DateLong, dateFormat);
- Start_Time = star;
- }
- /// <summary>
- /// 根据结束时间,修改开始时间
- /// 若开始时间有值,则不改动
- /// </summary>
- /// <param name="Start">开始时间</param>
- /// <param name="End">结束时间</param>
- /// <param name="DateLong">间隔长度</param>
- /// <param name="dateFormat">间隔单位</param>
- private void ChangStar(ref DateTime? Start, DateTime? End, int DateLong, DateFormat dateFormat) {
- if (Start.HasValue)
- return;
- DateLong = - DateLong;
- // 获取开始时间
- switch (dateFormat) {
- // 年份
- case DateFormat.Year:
- Start = End.Value.AddYears(DateLong);
- break;
- // 月份
- case DateFormat.Month:
- Start = End.Value.AddMonths(DateLong);
- break;
- // 天数
- case DateFormat.Day:
- Start = End.Value.AddDays(DateLong);
- break;
- // 小时
- case DateFormat.Hour:
- Start = End.Value.AddHours(DateLong);
- break;
- // 分钟
- case DateFormat.Minute:
- Start = End.Value.AddMinutes(DateLong);
- break;
- // 秒钟
- case DateFormat.Second:
- Start = End.Value.AddSeconds(DateLong);
- break;
- }
- }
- #endregion
- }
- /// <summary>
- /// 时间格式
- /// </summary>
- public enum DateFormat {
- /// <summary>
- /// 年份
- /// </summary>
- Year,
- /// <summary>
- /// 月份
- /// </summary>
- Month,
- /// <summary>
- /// 天数
- /// </summary>
- Day,
- /// <summary>
- /// 小时
- /// </summary>
- Hour,
- /// <summary>
- /// 分钟
- /// </summary>
- Minute,
- /// <summary>
- /// 秒钟
- /// </summary>
- Second
- }
- /// <summary>
- /// 时间区间
- /// </summary>
- public enum DateSection {
- /// <summary>
- /// 今天
- /// </summary>
- Today,
- /// <summary>
- /// 昨天
- /// </summary>
- Yesterday,
- /// <summary>
- /// 本周,星期天为第一天
- /// </summary>
- ThisWeek,
- /// <summary>
- /// 上周,星期天为第一天
- /// </summary>
- LastWeek,
- /// <summary>
- /// 本月
- /// </summary>
- ThisMonth,
- /// <summary>
- /// 上月
- /// </summary>
- LastMonth,
- /// <summary>
- /// 今年
- /// </summary>
- ThisYear,
- /// <summary>
- /// 去年
- /// </summary>
- LastYear
- }
- }
个人觉着,虽然代码一般般,但里面有不少小技巧还是很不错的,适合那些比我还新的新手学习一下,比如时间校验,,那个真的是伤透了心
如果大家发现了有什么bug,欢迎指出,或者有比较有趣的点子也欢迎互相交流,,,嗯,就酱紫,我去纠结TreeView控件绑值的问题,,
MVC查询数据接收及校验的更多相关文章
- .net mvc前台如何接收和解析后台的字典类型的数据 二分搜索算法 window.onunload中使用HTTP请求 网页关闭 OpenCvSharp尝试 简单爬虫
.net mvc前台如何接收和解析后台的字典类型的数据 很久没有写博客了,最近做了一个公司门户网站的小项目,其中接触到了一些我不会的知识点,今日事情少,便记录一下,当时想在网上搜索相关的内容,但是 ...
- [ASP.NET MVC] Controlle中的Aciton方法数据接收方式
POST数据接收方式包括: 1.request.Form:(逐个获取表单提交的数据); FormCollection: [HttpPost]public async Task<string> ...
- .net下MVC中使用Tuple分页查询数据
主要是在DAL层写查询分页的代码. 例如DAL层上代码: public Tuple<List<WxBindDto>, int> GetMbersInfo(int start, ...
- ASP.NET MVC 5 - 给数据模型添加校验器
在本节中将会给Movie模型添加验证逻辑.并且确保这些验证规则在用户创建或编辑电影时被执行. 拒绝重复 DRY ASP.NET MVC 的核心设计信条之一是DRY: "不要重复自己(DRY ...
- [转]ASP.NET MVC 5 - 给数据模型添加校验器
在本节中将会给Movie模型添加验证逻辑.并且确保这些验证规则在用户创建或编辑电影时被执行. 拒绝重复 DRY ASP.NET MVC 的核心设计信条之一是DRY: "不要重复自己(DRY ...
- Ibatis的resultMap和查询数据的对应关系
iBatis和MyBatis 中返回数据对应关系 直接进入主题,现在的项目改用MyBatis了,感觉跟iBatis还是不一样的,比如在判断空值上面,iBatis是有标签的<isNotEmpty& ...
- Asp.net MVC 传递数据 从前台到后台,包括单个对象,多个对象,集合
今天为大家分享下 Asp.net MVC 将数据从前台传递到后台的几种方式. 环境:VS2013,MVC5.0框架 1.基本数据类型 我们常见有传递 int, string, bool, double ...
- 学习ASP.NET MVC(七)——我的第一个ASP.NET MVC 查询页面
在本篇文章中,我将添加一个新的查询页面(SearchIndex),可以按书籍的种类或名称来进行查询.这个新页面的网址是http://localhost:36878/Book/ SearchIndex. ...
- ThinkPHP查询数据与CURD
一.创建连接 在配置文件中使用如下配置: /* 数据库设置 */ 'DB_TYPE' => 'mysql', // 数据库类型 'DB_HOST' => 'localhost', // 服 ...
随机推荐
- 8.8.2 Final关键字
final表示不可改变的含义 1.采用final 修饰的类不能被继承 2.采用final 修饰的方法不能被覆盖 3.采用final 修饰的变量不能被修改 4.final修饰的变量必须显示初始化(该 ...
- pwnable.kr brainfuck之write up
I made a simple brain-fuck language emulation program written in C. The [ ] commands are not impleme ...
- WireX:Android智能手机组成的DDoS僵尸网络
阿里聚安全小编曾多次报道了官方应用市场出现恶意软件的事件,让大家在下载APP的时候三思而后行. 最近多家安全公司组成的安全研究小组发现了一个新的.传播广泛的僵尸网络,它是由成千上万的Android智能 ...
- 【整合】input标签JS改变Value事件处理方法
某人需要在时间控件给文本框赋值时,触发事件函数.实现的效果: 1.文本框支持手工输入,通过用户输入修改值,手工输入结束后触发事件.阻塞在于失去焦点后才触发(输入过程中不触发事件) 2.通过JS方法修改 ...
- python+selenium自动化软件测试(第15章):基础实战(2)
#coding:utf-8 #for windows/py2.7 from time import sleep from selenium import webdriver browser = web ...
- 求最长公共前缀和后缀—基于KMP的next数组
KMP算法最主要的就是计算next[]算法,但是我们知道next[]求的是当前字符串之前的子字符串的最大前后缀数,但是有的时候我们需要比较字符串中前后缀最大数,比如 LeetCode的shortest ...
- Electron 实战桌面计算器应用
前言 Electron 是一个搭建跨平台桌面应用的框架,仅仅使用 JavaScript.HTML 以及 CSS,即可快速而容易地搭建一个原生应用.这对于想要涉及其他领域的开发者来说是一个非常大的福利. ...
- 使用 PUTTY 操作 Google Cloud
目的: 使用putty连接Google Cloud 实例. 总说: 首先要用 PuTTYgen生成 private key 和 public key, 之后 登录Google Cloud 将生成的 ...
- 深入剖析ConcurrentHashMap二
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt200 我们关注的操作有:get,put,remove 这3个操作.对于哈希表 ...
- 第1阶段——uboot分析之硬件初始化start_armboot函数(5)
start_armboot()分析:在start.S初始化后跳转到start_armboot实现第2阶段硬件相关的初始化(烧写擦除flash,网卡驱动,usb驱动,串口驱动,从FLASH读内核,启动内 ...