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', // 服 ...
随机推荐
- [目标检测]YOLO原理
1 YOLO 创新点: 端到端训练及推断 + 改革区域建议框式目标检测框架 + 实时目标检测 1.1 创新点 (1) 改革了区域建议框式检测框架: RCNN系列均需要生成建议框,在建议框上进行分类与回 ...
- java的引用数据类型,你知道吗???
有些人很清楚java的八种基本数据类型,但说到java的引用数据类型就不清楚了. Java的数据类型分为两大类,即基本数据类型和引用数据类型,在基本数据类型中有8种 基本数据类型(逻辑型-boolea ...
- Python3调用企业微信用于告警
前段时间利用py爬虫抓取一些网页信息,然后通过wxpy发送到微信群,以用作日常告警,感觉还是很方便. 但好景不长,我的小号微信被腾讯封了(很常见咯), 显示无法登录网页版微信,至今已经有半个多月了. ...
- django日期比较
from django.db import models from django.utils import timezone import datetime # Create your models ...
- 计算机程序的思维逻辑 (95) - Java 8的日期和时间API
本节继续探讨Java 8的新特性,主要是介绍Java 8对日期和时间API的增强,关于日期和时间,我们在之前已经介绍过两节了,32节介绍了Java 1.8以前的日期和时间API,主要的类是Date和 ...
- Python初学——pickle & set
pickle 存放数据 保存和提取python运算完的结果 首先import pickle模块 定义一个字典: a_dict={'da':111,2:[23,1,4],'23':{1:2,'d':'s ...
- HDU 6149 Valley Numer II 状压DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意:中文题目 解法:状压DP,dp[i][j]代表前i个低点,当前高点状态为j的方案数,然后枚 ...
- 【笔记】shellcode相关整理
0x01:shellcode定义 Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限.另外,Shellcode一般是作为数据发送给受攻击服务器 ...
- 手机端rem适应
这段时间做了几个手机版的项目,因为没有用框架,所以用rem来做适应,下面就分享一下 //第一种是比较简单的代码 (function(win) { resizeRoot(); function resi ...
- 探索JSP中的 "9大内置对象!"
1.什么是JSP内置对象? jsp内置对象就是Web容器创建的一组对象,我们都知道Tomcat可以看成是一种Web容器,所以我们可以知道所谓的内置对象Tomcat创建的,使用内置对象时可以不适用new ...