你还在用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);
- /// <summary>
- /// 根据查询条件获取
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- 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,里面很多高手,期待你的加入。