[Asp.Net]最近一个项目的总结

引言


项目到目前告一段落,目前进入测试阶段,下周就要去部署了。虽然项目不大,但是从头到尾都是自己一个人负责,在完成编码之后,对代码进行走查,命名规范,业务逻辑,代码优化等,能负责一个项目的整个编码,非常的兴奋啊。

技术

用到的技术:




















































技术 项目中使用该技术目的
ASP.NET 使用asp.net进行web端用户信息管理,对用户的增删改查,对签名样本的上传,下载Excel模版,导入用户信息。
webService 为签名客户端提供修改用户密码接口服务,下载签名样本接口服务,
windows服务 轮询数据库,对满足条件的dwg文件,从ftp服务器下载dwg文件至c盘缓存,获取签名样本文件,调用c++签名接口,对dwg文件进行签名。
ftp 使用serv-u进行ftp服务器搭建,对dwg文件进行上传下载。serv-u配置教程。[工具]Serv-U配置教程
jquery 使用ajax对用户信息的无刷新校验,主要用在登录页面,添加用户页面对信息的校验。
js 回车键触发登录事件。
jqueryui 上传前面样本,excel人员信息excel文件的弹出框。
uploadify上传组件 上传.sign文件和.xlsx文件。
NHibernate

对象/关系数据库映射工具

多层

IData:数据库操作接口

Data:数据库操作类

Business:业务逻辑层

Domain:简单领域层,包括Entities(数据库映射实体类)和Mapping(NHibernate映射xml文件)

Ui:人员信息管理web端

NHibernate

对象/关系数据库映射工具

NPOI

项目中用到com组件进行读取excel的,但是测试的时候,在x64系统上读取不了,没办法采用了NPOI组件。

AspNetPager

对人员列表进行分页。


工具


























工具 目的
VS2012 代码编写
动软代码生成器 根据NHibernate模版生成IData,Data,Business,Entities,Mapping代码生成
Serv-U ftp服务器搭建
SqlServer2012

数据库

windows
server2008
服务器环境虚拟机,测试用
Dependency
Walker
查看dll依赖,

[工具]推荐一款查看dll依赖工具



web端界面

该项目,为管理员使用,类似一个简单的管理工具。对样式要求不高就从网上找了一个样式,扒取的样式。

登录界面:

页面主要代码:

  1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="PYC.SignatureNX.Login" %>
2
3 <!DOCTYPE html>
4
5 <html xmlns="http://www.w3.org/1999/xhtml">
6 <head runat="server">
7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
8 <title>登录</title>
9 <link href="CSS/admin_login.css" rel="stylesheet" />
10 <script type="text/javascript" src="Scripts/jquery-1.10.2.js"></script>
11 <script type="text/javascript">
12 $(function () {
13 //页面加载,用户名文本框获得焦点
14 $("#txtCode").focus();
15 //密码框获得焦点,断用户是否存在
16 $("#txtPwd").focus(function () {
17 var strCode = $("#txtCode").val();
18 if (strCode == "") {
19 alert("请输入用户名");
20 $("#txtCode").focus();
21 return;
22 } else {
23 AjaxRequest(strCode, "", "Exist");
24 }
25
26 });
27 //单击登录按钮,验证密码是否存在,存在则登录,不存在重新输入用户密码
28 $("#btnLogin").click(function () {
29 var strCode = $("#txtCode").val();
30 var strPwd = $("#txtPwd").val();
31 if (strCode == "") {
32 alert("请输入用户名");
33 return;
34 } else if (strPwd == "") {
35 alert("请输入密码");
36 return;
37 } else {
38 AjaxRequest(strCode, strPwd, "SignIn");
39 }
40
41 });
42
43 });
44 //ajax请求,验证用户名,密码
45 function AjaxRequest(code, pwd, method) {
46 //拼接参数
47 var strData = "strCode=" + code
48 if (pwd != "") {
49 strData += "&strPwd=" + pwd;
50 }
51 $.ajax({
52 type: "POST",
53 url: "Ashx/Login.ashx?action=" + method,
54 data: strData,
55 contentType: "application/x-www-form-urlencoded",
56 dataType: "text",
57 success: function (data) {
58 if (data == "-1") {
59 alert("该用户不存在,请重新输入");
60 $("#txtCode").val("");
61 $("#txtCode").focus();
62 return false;
63 } else if (data == "0") {
64 alert("密码不正确,请重新输入");
65 $("#txtPwd").val("");
66 $("#txtPwd").focus();
67 return false;
68 } else if (data == "1") {
69 window.location.href = "Main.aspx";
70 }
71 },
72 //参数:XMLHttpRequest 对象、错误信息、(可选)捕获的异常对象。
73 error: function (XMLHttpRequest, textStatus, errorThrown) {
74 //请求失败,弹出错误状态码
75 alert(textStatus);
76 }
77 });
78 }
79 </script>
80 <script type="text/javascript">
81 //回车触发登录事件
82 function keyLogin() {
83 //获得用户名和密码
84 var strCode = $("#txtCode").val();
85 var strPwd = $("#txtPwd").val();
86 //如果按下回车键,此时用户名为空,则提示,用户名文本框获得焦点,并阻止提交
87 if (event.keyCode == 13 && strCode == "") {
88 alert("请输入用户名");
89 $("#txtCode").val("");
90 $("#txtCode").focus();
91 return;
92 } else if (event.keyCode == 13 && strPwd == "") {
93 //如果按下回车键,此时密码为空,则提示,密码文本框获得焦点,并阻止提交
94 alert("请输入密码");
95 $("#txtPwd").val("");
96 $("#txtPwd").focus();
97 return;
98 }
99 //如果按下回车键,并且用户名和密码都不为空,触发登录按钮的单击事件,进行提交验证
100 if (event.keyCode == 13 && strCode != "" && strPwd != "") //回车键的键值为13
101 document.getElementById("btnLogin").click(); //调用登录按钮的登录事件
102 }
103 </script>
104 </head>
105 <body onkeyup="keyLogin();">
106 <form id="form1" runat="server">
107 <div class="admin_login_wrap">
108 <h1>系统登录窗口</h1>
109 <div class="adming_login_border">
110 <div class="admin_input">
111
112 <ul class="admin_items">
113 <li>
114 <label for="user">用户名:</label>
115 <input type="text" name="txtCode" value="" id="txtCode" size="40" class="admin_input_style" />
116 </li>
117 <li>
118 <label for="pwd">密码:</label>
119 <input type="password" name="txtPwd" value="" id="txtPwd" size="40" class="admin_input_style" />
120 </li>
121 <li>
122 <input type="button" tabindex="3" id="btnLogin" value="登录" class="btn btn-primary" />
123 </li>
124 </ul>
125
126 </div>
127 </div>
128 </div>
129
130 </form>
131 </body>
132 </html>

Login.aspx

业务逻辑:用户名失去焦点时,进行用户名是否存在。使用ajax进行无刷新登录。
人员信息模版:

人员信息列表页面:

导入过程:

结果:

上传签名人样本:

单击人员列表中的上传,弹出上传签名样本的窗口。

页面主要代码:

  1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Main.aspx.cs" Inherits="PYC.SignatureNX.Main" %>
2
3 <!DOCTYPE html>
4 <%@ Register Assembly="AspNetPager" Namespace="Wuqi.Webdiyer" TagPrefix="webdiyer" %>
5 <html xmlns="http://www.w3.org/1999/xhtml">
6 <head runat="server">
7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
8 <title>用户信息</title>
9 <link href="CSS/common.css" rel="stylesheet" />
10 <link href="CSS/main.css" rel="stylesheet" />
11 <style type="text/css">
12 /*隐藏上传的进度条*/
13 .uploadify-queue
14 {
15 display: none;
16 }
17 /*查询框中灰色字体样式*/
18 .search
19 {
20 color: gray;
21 }
22 </style>
23 <script type="text/javascript" src="Scripts/jquery-1.10.2.js"></script>
24 <link href="Scripts/uploadify/css/uploadify.css" rel="stylesheet" />
25 <script type="text/javascript" src="Scripts/uploadify/js/uploadify3.2.1/jquery.uploadify.js"></script>
26 <link href="Scripts/JqueryUI/css/redmond/jquery-ui-1.10.4.custom.css" rel="stylesheet" />
27 <script type="text/javascript" src="Scripts/JqueryUI/js/jquery-ui-1.10.4.custom.js"></script>
28 <script type="text/javascript">
29 $(function () {
30 //初始化批量导入弹出框
31 OpenDialog("dialogxls", "上传批导人员信息", false);
32
33 //初始化dialog
34 OpenDialog("dialog", "上传签名样本", true);
35 });
36 function OpenDialog(id, title, isContainsUpload) {
37 //弹出框的初始化方法
38 $("#" + id).dialog({
39
40 // 初始化之后,是否立即显示对话框,默认为 true
41 autoOpen: false,
42
43 //设置弹出框的高度 400px
44 width: 400,
45
46 //是否模式对话框,默认为 false
47 modal: true,
48
49 //是否允许拖动,默认为 true
50 draggable: true,
51
52 //是否可以调整对话框的大小,默认为 true
53 resizable: true,
54
55 //弹出框的标题
56 title: title,
57 position: "center",
58 close: function () {
59 if (isContainsUpload == true) {
60 //注意jquery下检查一个元素是否存在必须使用 .length >0 来判断
61 if ($(‘#btnUpload‘).length > 0) {
62 //如果存在,则将其销毁
63 $(‘#btnUpload‘).uploadify(‘destroy‘);
64 }
65 } else {
66 //注意jquery下检查一个元素是否存在必须使用 .length >0 来判断
67 if ($(‘#btnUploadXLS‘).length > 0) {
68 //如果存在,则将其销毁
69 $(‘#btnUploadXLS‘).uploadify(‘destroy‘);
70 }
71
72 }
73 }
74 });
75 }
76 </script>
77 </head>
78 <body>
79 <div class="result-wrap">
80
81 <form id="form1" runat="server">
82 <div>
83 <table style="width: 100%;">
84 <tr>
85 <td>
86 <asp:Button ID="btnAdd" runat="server" Text="添加" CssClass="btn btn6" OnClick="btnAdd_Click" />&nbsp;&nbsp;<asp:Button CssClass="btn btn6" ID="btnDeleteMore" runat="server" Text="批量删除" OnClientClick="SelectUsers();" OnClick="btnDeleteMore_Click" />&nbsp;&nbsp;<input class="btn btn6" type="button" name="name" id="btnMoreImport" value="批量导入" />&nbsp;&nbsp;<asp:Button CssClass="btn btn6" ID="btnTemlpalteLoad" runat="server" Text="批导模版下载" OnClick="btnTemlpalteLoad_Click" />&nbsp;&nbsp;<%--<a href="SignTest.aspx">签名信息列表</a>--%><asp:Button Text="批量启用" runat="server" ID="btnStartMore" CommandName="Start" CssClass="btn btn6" OnClientClick="SelectUsers();" OnClick="btnStartMore_Click" />&nbsp;&nbsp;<asp:Button Text="批量停用" runat="server" OnClick="btnStartMore_Click" CssClass="btn btn6" OnClientClick="SelectUsers();" CommandName="Stop" ID="btnStopMore" /></td>
87 <td align="right">
88 <asp:TextBox runat="server" Text="请输入查询关键字" ID="txtSearch" CssClass="search" />&nbsp;&nbsp;<asp:Button Text="查询" runat="server" CssClass="btn btn6" ID="btnSearch" OnClick="btnSearch_Click" /></td>
89 </tr>
90 </table>
91 <asp:HiddenField runat="server" ID="hdFieldIds" Value="" />
92 <br />
93
94 <div class="result-content">
95 <asp:Repeater ID="RptUserList" runat="server" OnItemDataBound="RptUserList_ItemDataBound">
96 <HeaderTemplate>
97 <table class="result-tab" style="width: 100%; text-align: center;" id="tbUsers">
98 <tr>
99 <th width="5%">
100 <a href="javascript:void(0)" id="lnkSelectAll">全选</a> </th>
101 <th width="5%">序号</th>
102 <th>用户名</th>
103 <th>签名人姓名</th>
104 <th>签名人样本</th>
105 <th>状态</th>
106 <th>操作</th>
107 </tr>
108 </HeaderTemplate>
109 <ItemTemplate>
110 <tr>
111 <td>
112 <input type="checkbox" name="name" value=‘<%#Eval("Sign_Code") %>‘ />
113 </td>
114 <td>
115 <asp:Literal ID="ltlItemNo" runat="server" />
116 </td>
117 <td><%#Eval("Sign_Code") %></td>
118 <td><%#Eval("Sign_Name") %></td>
119 <td id="td<%#Eval("Sign_Code") %>">
120 <asp:Literal Text="" ID="ltlSignSample" runat="server" />
121 </td>
122 <td>
123 <asp:LinkButton OnClick="lnkState_Click" ID="lnkState" Text="" runat="server" /></td>
124 <td>
125 <asp:LinkButton CommandArgument=‘<%#Eval("Sign_Code") %>‘ CommandName="Edit" Text="编辑" ID="lnkBtn" OnClick="lnkBtn_Click" runat="server" />&nbsp;&nbsp;
126 <asp:LinkButton Text="删除" CommandArgument=‘<%#Eval("Sign_Code") %>‘ CommandName="Delete" OnClick="lnkBtn_Click" runat="server" />
127 </td>
128
129 </tr>
130 </ItemTemplate>
131 <FooterTemplate>
132 </table>
133 </FooterTemplate>
134 </asp:Repeater>
135 </div>
136 <div id="dialogxls" title="上传Excel文件" style="text-align: center; display: none;">
137 <input type="button" name="name" id="btnUploadXLS" value="上传" />
138 <span id="spanMsg">(只能上传.xlsx格式文件)</span>
139 </div>
140 <div id="dialog" title="上传签名样本" style="text-align: center; display: none;">
141 <input type="button" name="name" id="btnUpload" value="上传样本" />
142 <span>(只能上传.sign格式文件)</span>
143 </div>
144
145 </div>
146
147
148 <div class="list-page">
149 <%-- 分页样式一 首页 上一页 下一页 尾页--%>
150 <webdiyer:AspNetPager ID="AspNetPager1" runat="server"
151 CustomInfoHTML="共%PageCount%页,当前为第%CurrentPageIndex%页,每页%PageSize%条,共%RecordCount%条"
152 FirstPageText="首页"
153 LastPageText="尾页"
154 NextPageText="下一页"
155 PageIndexBoxType="TextBox"
156 PrevPageText="上一页"
157 ShowCustomInfoSection="Left"
158 ShowPageIndex="true"
159 ShowPageIndexBox="Always"
160 SubmitButtonText="Go"
161 SubmitButtonClass="right_d_btn"
162 TextAfterPageIndexBox="页"
163 TextBeforePageIndexBox="转到"
164 OnPageChanging="AspNetPager1_PageChanging"
165 AlwaysShow="True"
166 PageSize="10"
167 ShowMoreButtons="false"
168 HorizontalAlign="Center">
169 </webdiyer:AspNetPager>
170
171 </div>
172 </form>
173 </div>
174 </body>
175 </html>
176 <script type="text/javascript">
177
178 //全选,全不选
179 $("#lnkSelectAll").click(function () {
180 var txt = $(this).text();
181 var flag = false;
182 var strIds = "";
183 if (txt == "全选") {
184 $(this).text("全不选");
185 flag = true;
186 } else {
187 $(this).text("全选");
188 flag = false;
189 }
190 $("#tbUsers td :checkbox").each(function () {
191 this.checked = flag;
192 });
193 if (flag) {
194 $("#tbUsers td :checkbox").each(function (index) {
195 strIds += $(this).val() + ",";
196 });
197 } else {
198 strIds = "";
199 }
200 $("#hdFieldIds").val(strIds)
201
202 });
203 //选中的用户
204 function SelectUsers() {
205 var strIds = "";
206 $("#tbUsers td :checked").each(function (index) {
207 strIds += $(this).val() + ",";
208 });
209 $("#hdFieldIds").val(strIds)
210
211 }
212 //批量导入
213 $("#btnMoreImport").click(function () {
214 $("#dialogxls").dialog("open");
215 //上传
216 //上传插件初始化方法
217 $(‘#btnUploadXLS‘).uploadify({
218
219 //选择文件后是否自动上传,默认为true
220 ‘auto‘: true,
221 //选择文件按钮
222 ‘buttonClass‘: ‘some-class‘,
223 //是否开启调试模式
224 // ‘debug‘: true,
225 //设置按钮文本
226 ‘buttonText‘: ‘上传人员信息文件‘,
227 //以get方式提交,默认post
228 ‘method‘: ‘post‘,
229 //单个文件大小,0为无限制,可接受KB,MB,GB等单位的字符串值 上传大文件
230 ‘fileSizeLimit‘: ‘0‘,
231 ‘queueSizeLimit‘: 1,
232 //文件描述
233 ‘fileTypeDesc‘: ‘Files‘,
234 ‘multi‘: false,
235 //允许上传的文件类型 以分号分割
236 ‘fileTypeExts‘: ‘*.xlsx‘,
237 //当浏览文件对话框关闭触发
238 ‘onDialogClose‘: function (queueData) {
239 if (queueData.filesSelected>0) {
240 $("#spanMsg").html("正在处理上传的文件,请稍等....");
241 }
242 },
243 //FLash文件路径
244 ‘swf‘: ‘/Scripts/uploadify/js/uploadify3.2.1/uploadify.swf‘,
245 //上传文件处理后台页面
246 ‘uploader‘: ‘/Ashx/SampleUp.ashx?action=xlsUpload‘,
247 //上传成功后触发,每个文件都触发
248 ‘onUploadSuccess‘: function (file, data, response) {
249 if (data == "0") {
250 alert("人员信息有不合法数据,请检查后再次上传");
251 return false;
252 } else {
253 window.location = window.location;
254 }
255 }
256 });
257 });
258 var strSignCode = "";
259 function Upload(strCode) {
260 strSignCode = strCode;
261 //打开弹出框的按钮
262 //单击按钮 调用弹出框的open方法
263 $("#dialog").dialog("open");
264 //上传
265 //上传插件初始化方法
266 $(‘#btnUpload‘).uploadify({
267
268 //选择文件后是否自动上传,默认为true
269 ‘auto‘: true,
270 //选择文件按钮
271 ‘buttonClass‘: ‘some-class‘,
272
273 //设置按钮文本
274 ‘buttonText‘: ‘上传样本‘,
275 ‘method‘: ‘post‘,
276 //单个文件大小,0为无限制,可接受KB,MB,GB等单位的字符串值 上传大文件 可参考使用手册说明
277 ‘fileSizeLimit‘: ‘0‘,
278 ‘queueSizeLimit‘: 1,
279 //文件描述
280 ‘fileTypeDesc‘: ‘Files‘,
281 ‘multi‘: false,
282 //允许上传的文件类型 以分号分割
283 ‘fileTypeExts‘: ‘*.sign‘,
284 ‘onUploadStart‘: function (file) {
285 $("#btnUpload").uploadify("settings", "formData", { ‘code‘: strSignCode });
286 },
287 //FLash文件路径
288 ‘swf‘: ‘/Scripts/uploadify/js/uploadify3.2.1/uploadify.swf‘,
289 //上传文件处理后台页面
290 ‘uploader‘: ‘/Ashx/SampleUp.ashx?action=mainUpload‘,
291 //上传成功后触发,每个文件都触发
292 ‘onUploadSuccess‘: function (file, data, response) {
293 // window.location = window.location;
294 //上传成功,改变单元格内容,并停留在当前页面,可以避免刷新回到首页的情况。
295 $("#td" + strSignCode).html("<span>" + data + "</span>");
296 $("#dialog").dialog("close");
297 }
298 });
299 }
300
301 //查询相关方法
302 //获得焦点时,将文本框清空,并移除样式。
303 //失去焦点时,判断是否为空,为空则将提示信息重新填回,并添加样式。
304 $("#txtSearch").focus(function () {
305 if ($(this).val() == "请输入查询关键字") {
306 $(this).val("");
307 $(this).removeClass("search");
308 }
309 }).blur(function () {
310 if ($(this).val() == "") {
311 $(this).val("请输入查询关键字");
312 $(this).addClass("search");
313 }
314 });
315
316 </script>

Main.aspx

添加人员信息页面:
业务逻辑:签名样本应跟签名人编号相同。只有输入了编号,才允许上传,并且保证上传后的签名样本名称为只读的。

关于只读框和密码框应注意的地方:[Asp.net]说说密码框和只读框

输入用户名后:

用户编辑页面:

由于添加和编辑页面代码较简单,就不再贴代码,需注意的就是只读框的取值。

辅助类

  1   public class ExcelHelper
2 {
3 /// <summary>
4 /// 将Excel文件中的数据读出到DataTable中
5 /// </summary>
6 /// <param name="strFile">文件路径</param>
7 /// <returns>datatable</returns>
8 public static DataTable Excel2DataTable(string strFile, string strSheetName, string strTableName)
9 {
10 DataTable dt = new DataTable();
11 IWorkbook workbook = null;
12 using (FileStream fs = new FileStream(strFile, FileMode.Open, FileAccess.Read))
13 {
14 //office2003 HSSFWorkbook
15 //office2007 XSSFWorkbook初始化
16 workbook = new XSSFWorkbook(fs);
17 }
18 ISheet sheet = workbook.GetSheet(strSheetName);
19 //
20 dt = Export2DataTable(sheet, 0, false);
21 return dt;
22
23 }
24 /// <summary>
25 /// 将指定sheet中的数据导入到datatable中
26 /// </summary>
27 /// <param name="sheet">指定需要导出的sheet</param>
28 /// <param name="HeaderRowIndex">列头所在的行号,-1没有列头</param>
29 /// <param name="needHeader">是否需要列头</param>
30 /// <returns>DataTable</returns>
31 private static DataTable Export2DataTable(ISheet sheet, int HeaderRowIndex, bool needHeader)
32 {
33 DataTable dt = new DataTable();
34 XSSFRow headerRow = null;
35 int cellCount;
36 try
37 {
38 if (HeaderRowIndex < 0 || !needHeader)
39 {
40 headerRow = sheet.GetRow(0) as XSSFRow;
41 cellCount = headerRow.LastCellNum;
42 for (int i = headerRow.FirstCellNum; i <= cellCount; i++)
43 {
44 DataColumn column = new DataColumn(Convert.ToString(i));
45 dt.Columns.Add(column);
46 }
47 }
48 else
49 {
50 headerRow = sheet.GetRow(HeaderRowIndex) as XSSFRow;
51 cellCount = headerRow.LastCellNum;
52 for (int i = headerRow.FirstCellNum; i <= cellCount; i++)
53 {
54 ICell cell = headerRow.GetCell(i);
55 if (cell == null)
56 {
57 break;//到最后 跳出循环
58 }
59 else
60 {
61 //创建列
62 DataColumn column = new DataColumn(headerRow.GetCell(i).ToString());
63 //将列添加到datatable中
64 dt.Columns.Add(column);
65 }
66
67 }
68 }
69 //保存最后一行的索引
70 int intRowCount = sheet.LastRowNum;
71 for (int i = HeaderRowIndex + 1; i <= sheet.LastRowNum; i++)
72 {
73 XSSFRow xSSFRow = null;
74 if (sheet.GetRow(i) == null)
75 {
76 xSSFRow = sheet.CreateRow(i) as XSSFRow;
77 }
78 else
79 {
80 xSSFRow = sheet.GetRow(i) as XSSFRow;
81 }
82 DataRow dtRow = dt.NewRow();
83 for (int j = xSSFRow.FirstCellNum; j <= cellCount; j++)
84 {
85 //j=-1表示没有数据了
86 if (j != -1 && xSSFRow.GetCell(j) != null)
87 {
88 switch (xSSFRow.GetCell(j).CellType)
89 {
90 case CellType.Boolean:
91 dtRow[j] = Convert.ToString(xSSFRow.GetCell(j).BooleanCellValue);
92 break;
93 case CellType.Error:
94 dtRow[j] = ErrorEval.GetText(xSSFRow.GetCell(j).ErrorCellValue);
95 break;
96 case CellType.Formula:
97 switch (xSSFRow.GetCell(j).CachedFormulaResultType)
98 {
99
100 case CellType.Boolean:
101 dtRow[j] = Convert.ToString(xSSFRow.GetCell(j).BooleanCellValue);
102
103 break;
104 case CellType.Error:
105 dtRow[j] = ErrorEval.GetText(xSSFRow.GetCell(j).ErrorCellValue);
106
107 break;
108 case CellType.Numeric:
109 dtRow[j] = Convert.ToString(xSSFRow.GetCell(j).NumericCellValue);
110
111 break;
112 case CellType.String:
113 string strFORMULA = xSSFRow.GetCell(j).StringCellValue;
114 if (strFORMULA != null && strFORMULA.Length > 0)
115 {
116 dtRow[j] = strFORMULA.ToString();
117 }
118 else
119 {
120 dtRow[j] = null;
121 }
122 break;
123 default:
124 dtRow[j] = "";
125 break;
126 }
127 break;
128 case CellType.Numeric:
129 if (DateUtil.IsCellDateFormatted(xSSFRow.GetCell(j)))
130 {
131 dtRow[j] = DateTime.FromOADate(xSSFRow.GetCell(j).NumericCellValue);
132 }
133 else
134 {
135 dtRow[j] = Convert.ToDouble(xSSFRow.GetCell(j).NumericCellValue);
136 }
137 break;
138 case CellType.String:
139 string str = xSSFRow.GetCell(j).StringCellValue;
140 if (!string.IsNullOrEmpty(str))
141 {
142
143 dtRow[j] = Convert.ToString(str);
144 }
145 else
146 {
147 dtRow[j] = null;
148 }
149 break;
150 default:
151 dtRow[j] = "";
152 break;
153 }
154 }
155 else
156 {
157 break;
158 }
159 }
160 //将行加入datatable中
161 dt.Rows.Add(dtRow);
162 }
163 }
164 catch (Exception ex)
165 {
166 throw ex;
167 }
168 return dt;
169 }
170 /// <summary>
171 /// 将DataTable中的数据导入Excel文件中
172 /// </summary>
173 /// <param name="dt"></param>
174 /// <param name="strFile"></param>
175 public static void DataTable2Excel(DataTable dt, string strFile, string strSheetName)
176 {
177 IWorkbook workbook = new XSSFWorkbook();
178 ISheet sheet = workbook.CreateSheet(strSheetName);
179 IRow header = sheet.CreateRow(0);
180 for (int i = 0; i < dt.Columns.Count; i++)
181 {
182 ICell cell = header.CreateCell(i);
183 cell.SetCellValue(dt.Columns[i].ColumnName);
184 }
185 //数据
186 for (int i = 0; i < dt.Rows.Count; i++)
187 {
188 IRow row = sheet.CreateRow(i + 1);
189 for (int j = 0; j < dt.Columns.Count; j++)
190 {
191 ICell cell = row.CreateCell(j);
192 cell.SetCellValue(dt.Rows[i][j].ToString());
193 }
194 }
195 MemoryStream stream = new MemoryStream();
196 workbook.Write(stream);
197 byte[] buffer = stream.ToArray();
198 using (FileStream fs = new FileStream(strFile, FileMode.Create, FileAccess.Write))
199 {
200 fs.Write(buffer, 0, buffer.Length);
201 fs.Flush();
202 }
203 }
204 /// <summary>
205 /// 获取单元格类型
206 /// </summary>
207 /// <param name="xSSFCell">单元格</param>
208 /// <returns>object</returns>
209 private static object GetValueType(XSSFCell xSSFCell)
210 {
211 if (xSSFCell == null)
212 {
213 return null;
214 }
215 switch (xSSFCell.CellType)
216 {
217 case CellType.Blank:
218 return null;
219 case CellType.Boolean:
220 return xSSFCell.BooleanCellValue;
221 case CellType.Error:
222 return xSSFCell.ErrorCellValue;
223
224 case CellType.Numeric:
225 return xSSFCell.NumericCellValue;
226 case CellType.String:
227 return xSSFCell.StringCellValue;
228 case CellType.Formula:
229 default:
230 return "=" + xSSFCell.StringCellValue;
231 }
232 }
233
234 }

ExcelHelper

  1   public class FTPHelper
2 {
3 #region 字段
4 /// <summary>
5 /// ftp地址,带ftp协议
6 /// </summary>
7 private string strFtpURI;
8 /// <summary>
9 /// ftp用户名
10 /// </summary>
11 private string strFtpUserID;
12 /// <summary>
13 /// ftp的ip地址
14 /// </summary>
15 private string strFtpServerIP;
16 /// <summary>
17 /// ftp用户登录密码
18 /// </summary>
19 private string strFtpPassword;
20 /// <summary>
21 /// ftp目录路径
22 /// </summary>
23 private string strFtpRemotePath;
24 #endregion
25
26 /// <summary>
27 /// 连接FTP服务器
28 /// </summary>
29 /// <param name="strFtpServerIP">FTP连接地址</param>
30 /// <param name="strFtpRemotePath">指定FTP连接成功后的当前目录, 如果不指定即默认为根目录</param>
31 /// <param name="strFtpUserID">用户名</param>
32 /// <param name="strFtpPassword">密码</param>
33 public FTPHelper(string strFtpServerIP, string strFtpRemotePath, string strFtpUserID, string strFtpPassword)
34 {
35 this.strFtpServerIP = strFtpServerIP;
36 this.strFtpRemotePath = strFtpRemotePath;
37 this.strFtpUserID = strFtpUserID;
38 this.strFtpPassword = strFtpPassword;
39 this.strFtpURI = "ftp://" + strFtpServerIP + strFtpRemotePath;
40 }
41
42 /// <summary>
43 /// 上载
44 /// </summary>
45 /// <param name="strFilename">本地文件路径</param>
46 /// <param name="strSavePath">ftp服务器文件保存路径</param>
47 public void Upload(string strFilename, string strSavePath)
48 {
49 FileInfo fileInf = new FileInfo(strFilename);
50 FtpWebRequest reqFTP;
51 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strSavePath + fileInf.Name));
52 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
53 reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
54 reqFTP.KeepAlive = false;
55 reqFTP.UseBinary = true;
56 reqFTP.Proxy = null;
57 reqFTP.ContentLength = fileInf.Length;
58 int buffLength = 2048;
59 byte[] buff = new byte[buffLength];
60 int contentLen;
61 FileStream fs = fileInf.OpenRead();
62 try
63 {
64 Stream strm = reqFTP.GetRequestStream();
65 contentLen = fs.Read(buff, 0, buffLength);
66 while (contentLen != 0)
67 {
68 strm.Write(buff, 0, contentLen);
69 contentLen = fs.Read(buff, 0, buffLength);
70 }
71 strm.Close();
72 fs.Close();
73 }
74 catch (Exception ex)
75 {
76 throw new Exception(ex.Message);
77 }
78 }
79 /// <summary>
80 /// 上载
81 /// </summary>
82 /// <param name="strFilename">本地文件路径</param>
83 /// <param name="strSavePath">ftp服务器文件保存路径</param>
84 /// <param name="strStrOldName">ftp服务器文件保存的名字</param>
85 public void Upload(string strFilename, string strSavePath, string strStrOldName)
86 {
87 FileInfo fileInf = new FileInfo(strFilename);
88 FtpWebRequest reqFTP;
89 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strSavePath + strStrOldName));
90 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
91 reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
92 reqFTP.KeepAlive = false;
93 reqFTP.UseBinary = true;
94 reqFTP.Proxy = null;
95 reqFTP.ContentLength = fileInf.Length;
96 int buffLength = 2048;
97 byte[] buff = new byte[buffLength];
98 int contentLen;
99 FileStream fs = fileInf.OpenRead();
100 try
101 {
102 Stream strm = reqFTP.GetRequestStream();
103 contentLen = fs.Read(buff, 0, buffLength);
104 while (contentLen != 0)
105 {
106 strm.Write(buff, 0, contentLen);
107 contentLen = fs.Read(buff, 0, buffLength);
108 }
109 strm.Close();
110 fs.Close();
111 }
112 catch (Exception ex)
113 {
114 throw new Exception(ex.Message);
115 }
116 }
117 /// <summary>
118 /// 下载
119 /// </summary>
120 /// <param name="strFilePath">本地保存路径</param>
121 /// <param name="strFileName">文件名</param>
122 /// <param name="strFileName">本地临时名称</param>
123 public void Download(string strFilePath, string strFileName, string strLocalName)
124 {
125 try
126 {
127 FileStream outputStream = new FileStream(strFilePath + strLocalName, FileMode.Create);
128 FtpWebRequest reqFTP;
129 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strFileName));
130 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
131 reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
132 reqFTP.UseBinary = true;
133 reqFTP.UsePassive = true;
134 reqFTP.Proxy = null;
135 FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
136 Stream ftpStream = response.GetResponseStream();
137 long cl = response.ContentLength;
138 int bufferSize = 2048;
139 int readCount;
140 byte[] buffer = new byte[bufferSize];
141 readCount = ftpStream.Read(buffer, 0, bufferSize);
142 while (readCount > 0)
143 {
144 outputStream.Write(buffer, 0, readCount);
145 readCount = ftpStream.Read(buffer, 0, bufferSize);
146 }
147 ftpStream.Close();
148 outputStream.Close();
149 response.Close();
150 }
151 catch (Exception ex)
152 {
153 //记录日志
154 Common.LogHelper.WriteLog("文件下载异常:" + ex.Message);
155 }
156 }
157 /// <summary>
158 /// 下载
159 /// </summary>
160 /// <param name="strFilePath">本地保存路径</param>
161 /// <param name="strFileName">文件名</param>
162 public void Download(string strFilePath, string strFileName)
163 {
164 try
165 {
166 FileStream outputStream = new FileStream(strFilePath + strFileName, FileMode.Create);
167 FtpWebRequest reqFTP;
168 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strFileName));
169 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
170 reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
171 reqFTP.UseBinary = true;
172 reqFTP.UsePassive = true;
173 reqFTP.Proxy = null;
174 FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
175 Stream ftpStream = response.GetResponseStream();
176 long cl = response.ContentLength;
177 int bufferSize = 2048;
178 int readCount;
179 byte[] buffer = new byte[bufferSize];
180 readCount = ftpStream.Read(buffer, 0, bufferSize);
181 while (readCount > 0)
182 {
183 outputStream.Write(buffer, 0, readCount);
184 readCount = ftpStream.Read(buffer, 0, bufferSize);
185 }
186 ftpStream.Close();
187 outputStream.Close();
188 response.Close();
189 }
190 catch (Exception ex)
191 {
192 //记录日志
193 Common.LogHelper.WriteLog("文件下载异常:" + ex.Message);
194 }
195 }
196 /// <summary>
197 /// 删除文件
198 /// </summary>
199 /// <param name="strFileName">文件名</param>
200 public void Delete(string strFileName)
201 {
202 try
203 {
204 FtpWebRequest reqFTP;
205 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strFileName));
206 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
207 reqFTP.Method = WebRequestMethods.Ftp.DeleteFile;
208 reqFTP.KeepAlive = false;
209 string result = String.Empty;
210 FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
211 long size = response.ContentLength;
212 Stream datastream = response.GetResponseStream();
213 StreamReader sr = new StreamReader(datastream);
214 result = sr.ReadToEnd();
215 sr.Close();
216 datastream.Close();
217 response.Close();
218 }
219 catch (Exception ex)
220 {
221 throw new Exception(ex.Message);
222 }
223 }
224
225 /// <summary>
226 /// 获取当前目录下明细(包含文件和文件夹)
227 /// </summary>
228 /// <returns></returns>
229 public string[] GetFilesDetailList()
230 {
231 try
232 {
233 StringBuilder result = new StringBuilder();
234 FtpWebRequest ftp;
235 ftp = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI));
236 ftp.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
237 ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
238 WebResponse response = ftp.GetResponse();
239 StreamReader reader = new StreamReader(response.GetResponseStream());
240 string line = reader.ReadLine();
241 line = reader.ReadLine();
242 line = reader.ReadLine();
243 while (line != null)
244 {
245 result.Append(line);
246 result.Append("\n");
247 line = reader.ReadLine();
248 }
249 result.Remove(result.ToString().LastIndexOf("\n"), 1);
250 reader.Close();
251 response.Close();
252 return result.ToString().Split(‘\n‘);
253 }
254 catch (Exception ex)
255 {
256 throw new Exception(ex.Message);
257 }
258 }
259
260 /// <summary>
261 /// 获取FTP文件列表(包括文件夹)
262 /// </summary>
263 /// <param name="strUrl"></param>
264 /// <returns></returns>
265 private string[] GetAllList(string strUrl)
266 {
267 List<string> list = new List<string>();
268 FtpWebRequest req = (FtpWebRequest)WebRequest.Create(new Uri(strUrl));
269 req.Credentials = new NetworkCredential(strFtpPassword, strFtpPassword);
270 req.Method = WebRequestMethods.Ftp.ListDirectory;
271 req.UseBinary = true;
272 req.UsePassive = true;
273 try
274 {
275 using (FtpWebResponse res = (FtpWebResponse)req.GetResponse())
276 {
277 using (StreamReader sr = new StreamReader(res.GetResponseStream()))
278 {
279 string s;
280 while ((s = sr.ReadLine()) != null)
281 {
282 list.Add(s);
283 }
284 }
285 }
286 }
287 catch (Exception ex)
288 {
289 throw (ex);
290 }
291 return list.ToArray();
292 }
293
294 /// <summary>
295 /// 获取当前目录下文件列表(不包括文件夹)
296 /// </summary>
297 public string[] GetFileList(string strUrl)
298 {
299 StringBuilder result = new StringBuilder();
300 FtpWebRequest reqFTP;
301 try
302 {
303 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strUrl));
304 reqFTP.UseBinary = true;
305 reqFTP.Credentials = new NetworkCredential(strFtpPassword, strFtpPassword);
306 reqFTP.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
307 WebResponse response = reqFTP.GetResponse();
308 StreamReader reader = new StreamReader(response.GetResponseStream());
309 string line = reader.ReadLine();
310 while (line != null)
311 {
312
313 if (line.IndexOf("<DIR>") == -1)
314 {
315 result.Append(Regex.Match(line, @"[\S]+ [\S]+", RegexOptions.IgnoreCase).Value.Split(‘ ‘)[1]);
316 result.Append("\n");
317 }
318 line = reader.ReadLine();
319 }
320 result.Remove(result.ToString().LastIndexOf(‘\n‘), 1);
321 reader.Close();
322 response.Close();
323 }
324 catch (Exception ex)
325 {
326 throw (ex);
327 }
328 return result.ToString().Split(‘\n‘);
329 }
330
331 /// <summary>
332 /// 判断当前目录下指定的文件是否存在
333 /// </summary>
334 /// <param name="strRemoteFileName">远程文件名</param>
335 public bool FileExist(string strRemoteFileName)
336 {
337 string[] fileList = GetFileList("*.*");
338 foreach (string str in fileList)
339 {
340 if (str.Trim() == strRemoteFileName.Trim())
341 {
342 return true;
343 }
344 }
345 return false;
346 }
347
348 /// <summary>
349 /// 创建文件夹
350 /// </summary>
351 /// <param name="strDirName">目录名</param>
352 public void MakeDir(string strDirName)
353 {
354 FtpWebRequest reqFTP;
355 try
356 {
357 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strDirName));
358 reqFTP.Method = WebRequestMethods.Ftp.MakeDirectory;
359 reqFTP.UseBinary = true;
360 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
361 FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
362 Stream ftpStream = response.GetResponseStream();
363 ftpStream.Close();
364 response.Close();
365 }
366 catch (Exception ex)
367 { Common.LogHelper.WriteLog("ftp服务器创建目录异常:" + ex.Message); }
368 }
369
370 /// <summary>
371 /// 获取指定文件大小
372 /// </summary>
373 public long GetFileSize(string strFilename)
374 {
375 FtpWebRequest reqFTP;
376 long fileSize = 0;
377 try
378 {
379 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strFilename));
380 reqFTP.Method = WebRequestMethods.Ftp.GetFileSize;
381 reqFTP.UseBinary = true;
382 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
383 FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
384 Stream ftpStream = response.GetResponseStream();
385 fileSize = response.ContentLength;
386 ftpStream.Close();
387 response.Close();
388 }
389 catch (Exception ex)
390 { throw ex; }
391 return fileSize;
392 }
393
394 /// <summary>
395 /// 更改文件名
396 /// </summary>
397 public void ReName(string strCurrentFilename, string strNewFilename)
398 {
399 FtpWebRequest reqFTP;
400 try
401 {
402 reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(strFtpURI + strCurrentFilename));
403 reqFTP.Method = WebRequestMethods.Ftp.Rename;
404 reqFTP.RenameTo = strNewFilename;
405 reqFTP.UseBinary = true;
406 reqFTP.Credentials = new NetworkCredential(strFtpUserID, strFtpPassword);
407 FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
408 Stream ftpStream = response.GetResponseStream();
409 ftpStream.Close();
410 response.Close();
411 }
412 catch (Exception ex)
413 { throw ex; }
414 }
415
416 /// <summary>
417 /// 移动文件
418 /// </summary>
419 public void MovieFile(string strCurrentFilename, string strNewDirectory)
420 {
421 ReName(strCurrentFilename, strNewDirectory);
422 }
423
424 /// <summary>
425 /// 切换当前目录
426 /// </summary>
427 /// <param name="bIsRoot">true:绝对路径 false:相对路径</param>
428 public void GotoDirectory(string strDirectoryName, bool bIsRoot)
429 {
430 if (bIsRoot)
431 {
432 strFtpRemotePath = strDirectoryName;
433 }
434 else
435 {
436 strFtpRemotePath += strDirectoryName + "/";
437 }
438 strFtpURI = "ftp://" + strFtpServerIP + "/" + strFtpRemotePath + "/";
439 }
440 }

FTPHelper

Windows服务轮询

代码很简单,这里说明一下需要注意的地方,由于要调用c++动态链接库,并不是所有的异常信息都能catch到,所以在遇到bug的时候,比如dwg文件错误,就会造成服务停止,为了不让用户手动进入服务器进行手动启用,弄了一个exe程序,监听该服务是否启用,如果停用了,隔一段时间进行再次启用。

总结

由于该项目,客户只有管理员一个人使用,所以对项目的要求并不高,便宜我了,通过该项目,学到很多东西,之前也就负责功能模块,很没意思,不过这种从前端,到后台到数据库,都是自己弄的还是很有成就感的。

下周要去给客户部署了,最近一直在测试,一直在优化代码,轮询这块本来就是很费性能的,所以能想到的优化都用上了。

项目很小,也没什么要求只要能实现就可以,所以就随意发挥了。就当练练手了。

时间: 2024-08-07 04:31:39

[Asp.Net]最近一个项目的总结的相关文章

对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(4)

chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对此项目的理解.分为如下几篇: ● 对一个前端使用AngularJ

对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(3)

chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对此项目的理解.分为如下几篇: ● 对一个前端使用AngularJ

对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(1)

chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对此项目的理解.分为如下几篇: ● 对一个前端使用AngularJ

对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(2)

chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对此项目的理解.分为如下几篇: ● 对一个前端使用AngularJ

图文详解远程部署ASP.NET MVC 5项目

原文:图文详解远程部署ASP.NET MVC 5项目 话外篇: 由于感觉自己的机器比较慢,配置不好,所以最近想把之前的项目部署到实验室的服务器上,但是由于常不在实验室,所以在想能不能远程部署.因此今天专门研究了一下具体的过程,下面和大家分享一下.本人新手,还望大虾勿喷,有什么问题,还望高手指点. 一.本文实验环境: Windows Server 2012 R2 SQL Server 2012 Express Visual Studio 2013 项目为:ASP.NET MVC 5.0,使用的是L

使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus

最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错误出现,心中一万只草泥马奔腾而来,这也叫支持吗,这个问题是Visual Studio造成的,不相信的话可以使用Xamarin.Studio创建的asp.net项目,部署过程非常顺利,没有遇到什么问题:本文就是为你解开这个结,如何Visual Studio 2015搞定ASP.NET MVC 5项目的

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)

这个系列已经写了5篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [Asp.net 5] DependencyInjection项目代码分析3-Ninject [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1) [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2) 如果想

在ASP.NET Web API项目中使用Hangfire实现后台任务处理

当前项目中有这样一个需求:由前端用户的一个操作,需要触发到不同设备的消息推送.由于推送这个具体功能,我们采用了第三方的服务.而这个服务调用有时候可能会有延时,为此,我们希望将消息推送与用户前端操作实现异步执行,就是希望在后台自动执行,不阻塞前端用户的操作,而且最好能实现失败重试等功能. 经过一些研究比较,我们发现使用Hangfire这个组件可以较好地实现这个需求.为了给大家做一个演示,我这里简化了代码,做一个范例程序. 我在这里不准备详细介绍Hangfire的基本用法,有兴趣的同学们可以参考官方

ASP.NET MVC搭建项目后台UI框架—7、统计报表

ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NET MVC搭建项目后台UI框架—4.tab多页签支持 ASP.NET MVC搭建项目后台UI框架—5.Demo演示Controller和View的交互 ASP.NET MVC搭建项目后台UI框架—6.客户管理(添加.修改.查询.分页) ASP.NET MVC搭建项目后台UI框架—7.统计报表 本节,我将通