你还在用webforms拖拉控件,你还在用拖拉Ajax Control Toolkit,甚或DeveloperExpress,你Out了,快快跟我学习MVC4。
本节本人主要让那些觉得MVC比较难学的人明白,只要你想到了,就一般能做到。光有思想也不行,技术上一定要达到才行,那我问你个问题,Excel导入的时候,你怎么判断数据类型和长度?慢慢想吧!看看思想重要,还是技术重要。
首先我想上一张图,如下,还是调动一下胃口,因为无图无真相,谁看你写的博客
看见了吧,一个纯手工打造的,没有Jquery EasyUI,没有Ajax,普通的一个界面,就这一个普通的界面,所涉及的内容可不少呢。我们先看看界面代码
@using MVCRestServiceDemo.Models.Response; @using MVCRestServiceDemo.Models; @model DataResponse<person_info>; <script type="text/javascript"> jQuery(document).ready(function () { setRowBackColor(); $("#btnQuery").click(function () { /*查询*/ var pageIndex = 1; var pageSize = 12; var no = $("#txtNo").val(); var name = $("#txtName").val(); var sex = $("#ddlSex").val(); var condition = pageIndex + "_" + pageSize + "_" + no + "|" + name + "|" + sex; window.location.href = "/Home/GetArchiveInfoByCondition/" + condition; }); $("#btnDelete").click(function () { /*批量删除*/ var checkedCount = $("#tabArchiveInfo input[type='checkbox'][name!='chk_all'][checked]").length; if (checkedCount == 0) { alert("请选择要删除的数据!"); return; } $("#archiveInfoForm").submit(); /*提交Form*/ }); }); function checkall() { /*全选*/ if ($("#chkall").attr("checked")) { $(".mytable :checkbox").attr("checked", true); } else { $(".mytable :checkbox").attr("checked", false); } } function setRowBackColor() /*隔行变色*/ { var t = document.getElementById("tabArchiveInfo").getElementsByTagName("tr"); for (var i = 0; i < t.length; i++) { t[i].style.backgroundColor = (t[i].sectionRowIndex % 2 == 0) ? "#b7b3b3" : "#fff"; } } function setCheck(id) /*点击行选中或取消选中行首复选框*/ { $("#chk_" + id).attr("checked", !$("#chk_" + id).attr("checked")); } </script> <section class="features"> @using (Html.BeginForm("Delete", "Home", FormMethod.Post, new { id = "archiveInfoForm" })) { <table style="width: 96%; margin-bottom: 3px"> <tr> <td align="right">档案编号: </td> <td align="left"> @Html.TextBox("no", (ViewBag.No as string), new { id = "txtNo" }) </td> <td align="right">姓名: </td> <td align="left"> @Html.TextBox("name", (ViewBag.Name as string), new { id = "txtName" }) </td> <td align="right">性别: </td> <td align="left"> @Html.DropDownList("sex", (TempData["selectList"] as SelectList), new { id = "ddlSex" }) </td> <td aling="center"> <input id="btnQuery" type="button" value="查询" style="width: 80px" /> </td> </tr> </table> <table class="mytable" id="tabArchiveInfo"> <tr> <th> <center> @Html.CheckBox("chk_all", new { id = "chkall", onclick = "checkall()" }) </center> </th> <th> <center>档案编号</center> </th> <th> <center>姓名</center> </th> <th> <center>性别</center> </th> <th> <center>身份证号</center> </th> <th> <center>出生日期</center> </th> <th> <center>毕业院校</center> </th> <th> <center>学历</center> </th> <th> <center>专业</center> </th> <th> <center>操作</center> </th> </tr> @foreach (var personInfo in Model.DataList) { <tr onclick="setCheck('@personInfo.id')"> <td style="text-align: center;"> @Html.CheckBox(string.Concat("chk_", personInfo.id), false, new { id = string.Concat("chk_", personInfo.id), onclick = "setCheck('" + personInfo.id + "')" }) @Html.Hidden(string.Concat("hfd_", personInfo.id), personInfo.id) </td> <td> @personInfo.no </td> <td> @personInfo.name </td> <td> @(personInfo.sex == "1" ? "男" : "女") </td> <td> @personInfo.id_card </td> <td> @personInfo.birth </td> <td> @personInfo.graduate_school </td> <td> @personInfo.education_level </td> <td> @personInfo.professional </td> <td> <button type="submit" style="width: 60px; margin-right: 3px">修改</button> <button type="submit" style="width: 60px">删除</button> </td> </tr> } </table> <div class="divpager"> 共有 <font color="red" id="ft">@Model.TotalCount</font>条记录 当前是第 <font color="red">@Model.PageIndex</font> 页 共<font color="red">@Model.TotalPages</font>页 @if (Model.HasPreviousPage) { @Html.ActionLink("首页", "GetArchiveInfoByCondition", new { id = string.Join("_", "1", Model.PageSize, ViewBag.Conition) })<label> </label> @Html.ActionLink("上一页", "GetArchiveInfoByCondition", new { id = string.Join("_", Model.PageIndex - 1, Model.PageSize, ViewBag.Conition) })<label> </label> } else { <a>首页 </a> <a>上一页 </a> } @if (Model.HasNextPage) { @Html.ActionLink("下一页", "GetArchiveInfoByCondition", new { id = string.Join("_", Model.PageIndex + 1, Model.PageSize, ViewBag.Conition) })<label> </label> @Html.ActionLink("末页", "GetArchiveInfoByCondition", new { id = string.Join("_", Model.TotalPages, Model.PageSize, ViewBag.Conition) }) } else { <a>下一页 </a> <a>末页 </a> } </div> <div style="width: 96%; margin-top: 5px" align="right"> <button type="button" style="width: 80px;">增加</button> <button type="button" style="width: 80px" id="btnDelete">删除</button> </div> } </section>
通过界面代码,我们可以知道,我这个界面实现了界面上的隔行变色,全选/非全选,删除,查询(增加和修改功能将在下一节使用Ajax的时候介绍)功能。首先我们看第一段js。jQuery(document).ready这个函数里面实现的是隔行变色,查询,删除功能。我们先来看这个查询功能,设置window.location.href来实现页面刷新,达到查询效果。这个很容易理解,我们来看看查询代码
public ViewResult GetArchiveInfoByCondition(string id) { string[] pageValues = id.Split("_".ToCharArray()); int pageIndex = int.Parse(pageValues.ElementAt(0)); int pageSize = int.Parse(pageValues.ElementAt(1)); string[] searchValues = pageValues[2].Split("|".ToCharArray()); string no = searchValues.ElementAt(0) ?? string.Empty; string name = searchValues.ElementAt(1) ?? string.Empty; string sex = searchValues.ElementAt(2) ?? string.Empty; PersonRequest request = new PersonRequest() { No = no.Trim(), Name = name.Trim(), Sex = sex.Trim(), PageSize = pageSize, PageIndex = pageIndex }; ViewBag.No = request.No; ViewBag.Name = request.Name; ViewBag.Conition = string.Join("|", no.Trim(), name.Trim(), sex.Trim()); this.GetSexList(sex); string uri = baseAddress + "PersonInfo/GetByCondition"; DataResponse<person_info> personInfoList = dataService.GetData<DataResponse<person_info>, PersonRequest>(uri, request); return View("~/Views/Home/Index.cshtml", personInfoList); }
在这里我要说明的是MVC和Webforms不一样,当你刷新界面的时候,文本框和下拉的值都会被刷掉,所以在这里我们有ViewBag.No = request.No; ViewBag.Name = request.Name;意思是再把这些值重新帮回到页面,避免值被刷的情况。ViewBag.Conition = string.Join("|", no.Trim(), name.Trim(), sex.Trim());这个则是用来分页的时候传递的,因为分页的时候也要带上查询参数。至于这个DropDownList,
private void GetSexList(string selectedValue = "") { string uri = baseAddress + "PersonInfo/GetSexList"; List<codes> codeList = dataService.GetData<List<codes>>(uri); codeList.Insert(0, new codes() { data = string.Empty, display_content = "---请选择---" }); SelectList selectList = new SelectList(codeList, "data", "display_content", selectedValue); TempData["selectList"] = selectList; }
因为它在往页面返的时候就要设置选定(selectedvalue),SelectList的第四个参数。这个方法的参数selectedValue 是可选参数,4.0的新特性。所以这个无需放置在ViewBag中。我们来看看这个方法对应的WCF Restful
[OperationContract] [WebInvoke(UriTemplate = "Personinfo/GetByCondition", Method = "POST" , RequestFormat = WebMessageFormat.Json , ResponseFormat = WebMessageFormat.Json , BodyStyle = WebMessageBodyStyle.Bare)] DataResponse<person_info> GetPersonInfoByCondition(PersonRequest request);
public DataResponse<person_info> GetPersonInfoByCondition(PersonRequest request) { IQueryable<person_info> personInfos = misInfoEntities.person_info.Where(p => (string.IsNullOrEmpty(request.Name) ? true : p.name.Contains(request.Name.Trim())) && (string.IsNullOrEmpty(request.No) ? true : p.no.Contains(request.No.Trim())) && (string.IsNullOrEmpty(request.Sex) ? true : p.sex.Equals(request.Sex))); DataResponse<person_info> response = new DataResponse<person_info>(); response.TotalCount = personInfos.Count(); response.TotalPages = response.TotalCount % request.PageSize == 0 ? (response.TotalCount / request.PageSize) : (response.TotalCount / request.PageSize + 1); response.DataList = personInfos.AsEnumerable().OrderBy(p => p.no).Skip(request.PageSize * (request.PageIndex - 1)).Take(request.PageSize).ToList(); response.PageIndex = request.PageIndex; response.PageSize = request.PageSize; return response; }
在这里我们一次性把相关的数据都加载到了response 中,在这里我解释下RequestFormat = WebMessageFormat.Json这个和Response设置的一致,都是json格式,也就是请求和返回所传送的数据格式都是Json,WebMessageFormat是个枚举,另一个枚举值是Xml。还有WebMessageBodyStyle,在这里我选择Bare,选择不包裹,如果包裹,意味着传递给客户端的json格式就会找不到序列化对象,假如是个对象,那么就变为{"service方法名":{"键":"值"}}这种格式,导致客户端找不到反序列化对象。在这里我们还用到了另一个对象dataService,我们来看看
public class DataService { public T GetData<T, P>(string url, P parameter) where T : class, new() { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.Method = "POST"; httpWebRequest.ContentType = "application/json"; using (MemoryStream ms = new MemoryStream()) { if (parameter != null) { DataContractJsonSerializer parameterSerializer = new DataContractJsonSerializer(typeof(P)); Stream requestStream = httpWebRequest.GetRequestStream(); parameterSerializer.WriteObject(ms, parameter); byte[] byt = ms.ToArray(); requestStream.Write(byt, 0, byt.Length); } HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); T tObj = serializer.ReadObject(responseStream) as T; return tObj; } } public T DealData<T, P>(string url, P parameter) where T : struct { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.Method = "POST"; httpWebRequest.ContentType = "application/json"; using (MemoryStream ms = new MemoryStream()) { if (parameter != null) { DataContractJsonSerializer parameterSerializer = new DataContractJsonSerializer(typeof(P)); Stream requestStream = httpWebRequest.GetRequestStream(); parameterSerializer.WriteObject(ms, parameter); byte[] byt = ms.ToArray(); requestStream.Write(byt, 0, byt.Length); } HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); T tObj = (T)serializer.ReadObject(responseStream); return tObj; } } public T GetData<T>(string url) where T : class,new() { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.Method = "Get"; HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); T tObj = serializer.ReadObject(responseStream) as T; return tObj; } }
三个方法,第一个主要是执行POST方式的数据获取,第二个是执行POST方式的删除,修改,第三个则是执行Get方式。第三个方式的参数都是在URI中,所以无一和二那种POST序列化传值。Get典型的应用就是
public ActionResult Index() { ViewBag.Message = "WelCome to lilei's Mvc Demo!"; this.GetSexList(); return RedirectToAction("GetArchiveInfo"); } public ViewResult GetArchiveInfo() { string uri = string.Format(baseAddress + "PersonInfo/GetAll/{0}/{1}", 1, 12); ViewBag.Conition = string.Join("|", string.Empty, string.Empty, string.Empty); DataResponse<person_info> personInfoList = dataService.GetData<DataResponse<person_info>>(uri); return View("~/Views/Home/Index.cshtml", personInfoList); }
程序进来以后,先获取下拉列表数据,在跳转至GetArchiveInfo这个Action,看到了,它的URI传值是追在斜杠后面的。在这里我要说下这个TempData,这个东西在控制器只传递一次就销毁了,所以我在Index中获取的 TempData["selectList"] = selectList;再传到GetArchiveInfo是不会丢失的。我们来看看这个Get的Service
[OperationContract] [WebGet(UriTemplate = "PersonInfo/GetAll/{pageIndex}/{pageSize}", ResponseFormat = WebMessageFormat.Json)] DataResponse<person_info> GetPersonInfoList(string pageIndex,string pageSize);
采用的WebGet属性标注,在这里方法中的和URI中的参数名一定要匹配,而且get方式的参数一定要定义成string类型。OK,最后我们展望一下我们的删除,就洗洗睡了。看代码Service
[OperationContract] [WebInvoke(UriTemplate = "PersonInfo/Delete" ,BodyStyle=WebMessageBodyStyle.Bare ,RequestFormat=WebMessageFormat.Json ,ResponseFormat=WebMessageFormat.Json)] int Delete(List<string> ids); public int Delete(List<string> ids) { foreach (var id in ids) { person_info personInfo = misInfoEntities.person_info.Find(id); if (personInfo != null) { misInfoEntities.person_info.Remove(personInfo); } } return misInfoEntities.SaveChanges(); }
OK,很简单就不解释了,我们看看控制器,这是关键
public RedirectToRouteResult Delete(FormCollection fc) { string[] keys = fc.AllKeys; string[] chkKeys=keys.Where(k=>k.Contains("chk")&&k!="chk_all").ToArray(); List<string> idList = new List<string>(); foreach (var key in chkKeys) { if (fc[key].ToUpper().Contains("TRUE")) { idList.Add(fc[key.Replace("chk","hfd")]); } } string uri = baseAddress + "PersonInfo/Delete"; dataService.DealData<Int32, List<string>>(uri, idList); this.GetSexList(); return RedirectToAction("GetArchiveInfo"); }
看到了吧,我解释一下,Form提交,表单元素被提交到FormCollection(键值对),在这里我先获取所有Key,然后筛选出checkBox,循环遍历,如果包含值TRUE,注意这里如果checkbox选中,其值是"false,true",如果未选中其值是"false"。这个是MVC所决定的,我管不了。前台$("#tabArchiveInfo input[type='checkbox'][name!='chk_all'][checked]")这个意思是在id为tabArchiveInfo 的table元素中查找checkbox name不为chk_all并且状态是选中的Checkbox。如果没看懂,下一个Jquery 中文手册。OK,今天的内容就这么多,下次实战进入我们的Microsoft Ajax阶段。如果想要源码,请加入群205217091,里面很多高手,期待你的加入。