.NET MVC 學習筆記(六)—— 數據導入前端
在程序使用過程當中,有時候須要新增大量數據,這樣一條條數據去Add明顯不是很友好,這時候最好就是有一個導入功能,導入所須要的數據,下面咱們就一塊兒來看一下導入功能。node
一. 在導入以前,首先咱們須要下載模板,模板下載方法ajax
$("#btnDownloadTemplate") .click(function () { window.location.href = "@Url.Content("~/Content/ImportClientDataTemplate.xlsx")"; });
MVC .NET框架中該方法能夠在很容易的下載模板文件。正則表達式
若是是純前端框架,該方法則無效,運行效果爲直接在瀏覽器中打開模板文件,顯然不是咱們想要的。此時能夠使用如下辦法:sql
/* * 下載文件 */ window.downloadFile = function(sUrl) { //iOS devices do not support downloading. We have to inform user about this. if(/(iP)/g.test(navigator.userAgent)) { alert('Your device does not support files downloading. Please try again in desktop browser.'); return false; } //If in Chrome or Safari - download via virtual link click if(window.downloadFile.isChrome || window.downloadFile.isSafari) { //Creating new link node. var link = document.createElement('a'); link.href = sUrl; if(link.download !== undefined) { //Set HTML5 download attribute. This will prevent file from opening if supported. var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length); link.download = fileName; } //Dispatching click event. if(document.createEvent) { var e = document.createEvent('MouseEvents'); e.initEvent('click', true, true); link.dispatchEvent(e); return true; } } // Force file download (whether supported by server). if(sUrl.indexOf('?') === -1) { sUrl += '?download'; } window.open(sUrl, '_self'); return true; } window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
方法調用:chrome
downloadFile("../assets/template/Template.xlsx");
二. 數據導入數據庫
1. 導入按鈕:bootstrap
<div class="btn-group" style="text-align:right;width:82px"> <label class="input-group-btn"> <input id="btnSelectData" type="file" name="file" accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" style="left: -9999px; position: absolute;"> <span class="btn btn-default" style="border-radius:3px">導入會員</span> </label> </div>
2. 導入按鈕事件瀏覽器
// 選擇文件事件 $("#btnSelectData").change(function (e) { var file = e.target.files[0] || e.dataTransfer.files[0]; if (file) { $.bootstrapLoading.start( { loadingTips: "正在處理數據,請稍候...", opacity: 0.8, //loading頁面透明度 backgroundColor: "#000", TipsColor: "#555", }); // 獲取文件資源 var file = document.getElementById("btnSelectData").files[0]; var formData = new FormData(); formData.append('ExcelData', file); // 保存信息 $.ajax({ type: "POST", async: true, url: "@Url.Content("~/Client/ImportClientData")", data: formData, contentType: false, processData: false, mimeType: "multipart/form-data", success: function (response) { response = $.parseJSON(response); var option = { message: response.ResultMessage, title: response.ResultTitle }; Ewin.alert(option); if (response.ResultTitle == "Success") { $('.message-dialog').on('hide.bs.modal', function () { refresh(); }); } }, complete: function () { $.bootstrapLoading.end(); $("#btnSelectData").val(''); } }); } });
其中$.bootstrapLoading 是Loading功能,導入過程當中等待界面,須要導入PerfectLoad.js前端框架
3. Controller方法
/// <summary> /// 導入文件 /// </summary> /// <returns></returns> public JsonResult ImportClientData() { string result = String.Empty; String fileName = String.Empty; // 員工信息 List<ClientDomain> lsClient = new List<ClientDomain>(); try { if (Request.Files.Count > 0) { HttpPostedFileBase file = Request.Files["ExcelData"]; String filePath = @"../Upload/TempData/"; if (Directory.Exists(Server.MapPath(filePath)) == false)//若是不存在就建立file文件夾 { Directory.CreateDirectory(Server.MapPath(filePath)); } fileName = Server.MapPath(filePath) + file.FileName + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + Path.GetExtension(file.FileName); file.SaveAs(fileName); // 解析XML文件 //讀取xml XmlDocument xdoc = new XmlDocument(); xdoc.Load(Server.MapPath("/App_Data/ExcelTemplate.xml")); XmlElement root = xdoc.DocumentElement; //獲取根節點 XmlNode node = xdoc.SelectSingleNode("/Functions/Function[@name='Client']"); // 字段列表 List<ExcelField> lsExcelFields = new List<ExcelField>(); foreach (XmlNode item in node.ChildNodes) { String columnName = item.SelectSingleNode("columnName").InnerText; String fieldName = item.SelectSingleNode("fieldName").InnerText; lsExcelFields.Add(new ExcelField() { ColumnName = columnName, FieldName = fieldName }); } // 獲取Excel信息 for (int iIndex = 0; iIndex < NPOIHelper.GetNumberOfSheets(fileName); iIndex++) { // Read the CLP head information DataTable dtDatas = NPOIHelper.ReadExcel(fileName, iIndex, 0, 0); if (dtDatas == null) throw new Exception("Read excel error."); ClientDomain client = null; for (Int32 iRow = 0; iRow < dtDatas.Rows.Count; iRow++) { client = new ClientDomain(); // 遍歷全部屬性 lsExcelFields.ForEach(item => { String sValue = dtDatas.Rows[iRow][item.ColumnName].ToString(); Type t = client.GetType(); PropertyInfo propertyInfo = t.GetProperty(item.FieldName); if (propertyInfo.PropertyType == typeof(DateTime) || propertyInfo.PropertyType == typeof(DateTime?)) { if (!String.IsNullOrEmpty(sValue)) { propertyInfo.SetValue(client, DateTime.Parse(sValue), null); } } else if (propertyInfo.PropertyType == typeof(Decimal) || propertyInfo.PropertyType == typeof(Decimal?)) { propertyInfo.SetValue(client, Decimal.Parse(sValue), null); } else if (propertyInfo.PropertyType == typeof(Int32) || propertyInfo.PropertyType == typeof(Int32?)) { propertyInfo.SetValue(client, Int32.Parse(sValue), null); } else { propertyInfo.SetValue(client, sValue, null); } }); lsClient.Add(client); } } } //保存員工 result = service.SaveImportDatas(lsClient, CurrentLoginUser); // 刪除臨時文件 CommonMethod.DeleteFile(fileName); if (String.IsNullOrEmpty(result)) { LogHelper.LogOperate(String.Format("導入會員信息{0}條", lsClient.Count), Constant.OPEARTE_LOG_INFO, CurrentLoginUser); return new JsonResult() { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = new { ResultTitle = Constant.Result_Title_Success, ResultMessage = String.Format(MessageConstant.MESSAGE_IMPORT_SUCCESS, lsClient.Count) } }; } else { LogHelper.LogOperate(String.Format("導入會員信息失敗:{0}", result), Constant.OPEARTE_LOG_WARNING, CurrentLoginUser); return new JsonResult() { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = new { ResultTitle = Constant.Result_Title_Warning, ResultMessage = result } }; } } catch (Exception ex) { Log.SaveException(ex); return new JsonResult() { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = new { ResultTitle = Constant.Result_Title_Error, ResultMessage = ex.Message } }; } finally { // 刪除臨時文件 CommonMethod.DeleteFile(fileName); } }
ExcelField.cs
/// <summary> /// Excel Field /// </summary> [Serializable] [DataContract] public class ExcelField { [DataMember] public String ColumnName { get; set; } [DataMember] public String FieldName { get; set; } }
ExcelTemplate.xml
<?xml version="1.0" encoding="utf-8" ?> <Functions> <Function name="Client"> <field> <columnName>卡號</columnName> <fieldName>CardNo</fieldName> </field> <field> <columnName>姓名</columnName> <fieldName>UserName</fieldName> </field> <field> <columnName>性別</columnName> <fieldName>Sex</fieldName> </field> <field> <columnName>出生日期</columnName> <fieldName>Birthdate</fieldName> </field> <field> <columnName>手機號</columnName> <fieldName>Phone</fieldName> </field> <field> <columnName>地址</columnName> <fieldName>Address</fieldName> </field> <field> <columnName>積分</columnName> <fieldName>Score</fieldName> </field> <field> <columnName>等級</columnName> <fieldName>GradeCode</fieldName> </field> </Function> </Functions>
導入數據到數據庫
/// <summary> /// 導入數據 /// </summary> /// <param name="manager"></param> /// <param name="lsClient"></param> /// <param name="user"></param> /// <returns></returns> public string SaveImportDatas(DBManager manager, List<ClientDomain> lsClient, LoginUser user) { Int32 iCount = 50; Int32 iRunSize = (lsClient.Count / iCount) + 1; List<ClientDomain> newList = null; string result = String.Empty; String sUserId = user.RolesName; try { var waits = new List<EventWaitHandle>(); for (Int32 iIndex = 0; iIndex < iRunSize; iIndex++) { //計算每一個線程執行的數據 Int32 startIndex = (iIndex * iCount); Int32 iPage = iCount; if ((lsClient.Count - startIndex) < iCount) { iPage = (lsClient.Count - startIndex); } newList = lsClient.GetRange(startIndex, iPage); var handler = new ManualResetEvent(false); waits.Add(handler); ParamModel data = new ParamModel(); data.UserId = sUserId; data.Data = newList; data.manager = manager; new Thread(new ParameterizedThreadStart(ImportData)).Start(new Tuple<ParamModel, EventWaitHandle>(data, handler)); WaitHandle.WaitAll(waits.ToArray()); } } catch (Exception ex) { Log.SaveException(ex); result = ex.Message; } return result; } /// <summary> /// 導入數據 /// </summary> /// <param name="obj"></param> private void ImportData(Object obj) { var p = (Tuple<ParamModel, EventWaitHandle>)obj; ParamModel param = p.Item1 as ParamModel; String sUserId = param.UserId; DBManager manager = param.manager; List<ClientDomain> models = param.Data as List<ClientDomain>; models.ForEach(model => { List<ClientDomain> clients = ClientBiz.GetDomainByExactFilter(new ClientFilter() { CardNo = model.CardNo }) as List<ClientDomain>; if (clients == null || clients.Count == 0) { // 添加 model.CreateUser = sUserId; model.CreateDateTime = DateTime.Now; model.UpdateUser = sUserId; model.UpdateDateTime = DateTime.Now; String sql = DataHelper.GenerateInsertSQL(DbTableName.Client, model, new LoginUser() { Uid = sUserId }, DateTime.Now); manager.Execute(sql, model); } else { // 更新 model.Id = clients[0].Id; model.CreateUser = clients[0].CreateUser; model.CreateDateTime = clients[0].CreateDateTime; model.UpdateUser = sUserId; model.UpdateDateTime = DateTime.Now; String sql = DataHelper.GenerateUpdateAllFieldSQL(DbTableName.Client, model, new LoginUser() { Uid = sUserId }, DateTime.Now); manager.Execute(sql, model); } }); p.Item2.Set(); }
以上,數據導入功能完成。
如下程序運行效果
PS: 在Excel導入時,也能夠在ExcelTemplate.xml中配置一些字段Check的問題
例如:
<field> <columnName>卡號</columnName> <fieldName>CardNo</fieldName> <checkList> <!--NotNull:非空 Length:字段長度 Type:字段類型--> <NotNull>Y</NotNull> <Length>20</Length> <Type></Type> </checkList> </field>
ExcelField.cs & CheckModel.cs
/// <summary> /// Excel 字段 /// </summary> public class ExcelField { /// <summary> /// Excel列名 /// </summary> [DataMember] public String ColumnName { get; set; } /// <summary> /// 字段名稱 /// </summary> [DataMember] public String FieldName { get; set; } /// <summary> /// 檢測 /// </summary> [DataMember] public CheckModel CheckModel { get; set; } } /// <summary> /// 檢查項目 /// </summary> public class CheckModel { /// <summary> /// 非空 /// </summary> [DataMember] public String NotNull { get; set; } /// <summary> /// 字段長度檢測 /// </summary> [DataMember] public Int32 Length { get; set; } /// <summary> /// 字段類型 /// </summary> [DataMember] public String Type { get; set; } }
字段信息獲取以及字段檢查方法
/// <summary> /// 獲取全部Excel字段 /// </summary> /// <param name="functionName">功能名</param> /// <returns></returns> public static List<ExcelField> GetExcelFields(String functionName) { // 解析XML文件 //讀取xml XmlDocument xdoc = new XmlDocument(); xdoc.Load("Content/ExcelTemplate.xml"); XmlElement root = xdoc.DocumentElement; //獲取根節點 XmlNode node = xdoc.SelectSingleNode(String.Format("/Functions/Function[@name='{0}']", functionName)); // 字段列表 List<ExcelField> lsExcelFields = new List<ExcelField>(); foreach (XmlNode item in node.ChildNodes) { String columnName = item.SelectSingleNode("columnName").InnerText; String fieldName = item.SelectSingleNode("fieldName").InnerText; ExcelField excelField = new ExcelField(); // 列名 excelField.ColumnName = columnName; // 字段名 excelField.FieldName = fieldName; XmlNodeList childNode = item.SelectNodes("checkList"); if (childNode != null && childNode.Count != 0) { CheckModel check = new CheckModel(); // 非空判斷 check.NotNull = childNode[0].SelectSingleNode(Constant.Check_NotNull) == null ? "" : (childNode[0].SelectSingleNode(Constant.Check_NotNull).FirstChild == null ? "" : childNode[0].SelectSingleNode(Constant.Check_NotNull).FirstChild.Value); // 長度判斷 check.Length = childNode[0].SelectSingleNode(Constant.Check_Length) == null ? -1 : (childNode[0].SelectSingleNode(Constant.Check_Length).FirstChild == null ? -1 : Int32.Parse(childNode[0].SelectSingleNode(Constant.Check_Length).FirstChild.Value)); // 字段類型 check.Type = childNode[0].SelectSingleNode(Constant.Check_Type) == null ? "" : (childNode[0].SelectSingleNode(Constant.Check_Type).FirstChild == null ? "" : childNode[0].SelectSingleNode(Constant.Check_Type).FirstChild.Value); excelField.CheckModel = check; } lsExcelFields.Add(excelField); } return lsExcelFields; } /// <summary> /// 檢查字段 /// </summary> /// <param name="excel"></param> /// <param name="value"></param> /// <param name="iRowIndex"></param> /// <returns></returns> public static String CheckFieldValue(ExcelField excel, String value, Int32 iRowIndex) { StringBuilder sb = new StringBuilder(); try { // 非空判斷 if (Constant.NotNull_Y.Equals(excel.CheckModel.NotNull) && String.IsNullOrEmpty(value)) { sb.AppendLine(String.Format("第{0}行,{1}列值不能爲空。", iRowIndex, excel.ColumnName)); } // 長度判斷 if (excel.CheckModel.Length != -1 && (!String.IsNullOrWhiteSpace(value) && value.Length > excel.CheckModel.Length)) { sb.AppendLine(String.Format("第{0}行,{1}列值長度不能超過{2}。", iRowIndex, excel.ColumnName, excel.CheckModel.Length)); } // 類型判斷 if (!String.IsNullOrWhiteSpace(excel.CheckModel.Type)) { // 正則表達式 String pattern = String.Empty; // 表達式結果 Boolean bResult = true; switch (excel.CheckModel.Type) { // 正整數判斷 case Constant.Type_PositiveInteger: pattern = @"^[0-9]*[1-9][0-9]*$"; bResult = Regex.IsMatch(value ?? "", pattern); if (!bResult) { sb.AppendLine(String.Format("第{0}行,{1}列值應該輸入正整數。", iRowIndex, excel.ColumnName)); } break; case Constant.Type_Telephone: pattern = @"(/(/d{3,4}/)|/d{3,4}-|/s)?/d{7,14}"; bResult = Regex.IsMatch(value ?? "", pattern); if (!bResult) { sb.AppendLine(String.Format("第{0}行,{1}列值應該輸入正確電話號碼。", iRowIndex, excel.ColumnName)); } break; case Constant.Type_Email: pattern = @"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$"; bResult = Regex.IsMatch(value ?? "", pattern); if (!bResult) { sb.AppendLine(String.Format("第{0}行,{1}列值應該輸入正確郵箱。", iRowIndex, excel.ColumnName)); } break; } } return sb.ToString().Trim(); } catch (Exception ex) { return ex.Message; } } /// <summary> /// 設置屬性值 /// </summary> /// <param name="obj">對象</param> /// <param name="fieldName">字段名</param> /// <param name="value">字段值</param> public static void SetPropertyInfoValue(Object obj,String fieldName, String value) { Type t = obj.GetType(); PropertyInfo propertyInfo = t.GetProperty(fieldName); // 時間類型 if (propertyInfo.PropertyType == typeof(DateTime) || propertyInfo.PropertyType == typeof(DateTime?)) { if (!String.IsNullOrEmpty(value)) { DateTime dt; if (DateTime.TryParse(value, out dt)) { propertyInfo.SetValue(obj, dt, null); } } } // Decimal 類型 else if (propertyInfo.PropertyType == typeof(Decimal)|| propertyInfo.PropertyType == typeof(Decimal?)) { if (!String.IsNullOrEmpty(value)) { Decimal dValue; if (Decimal.TryParse(value, out dValue)) { propertyInfo.SetValue(obj, dValue, null); } } } // Int32 類型 else if (propertyInfo.PropertyType == typeof(Int32) || propertyInfo.PropertyType == typeof(Int32?)) { if (!String.IsNullOrEmpty(value)) { Int32 iValue; if (Int32.TryParse(value, out iValue)) { propertyInfo.SetValue(obj, iValue, null); } } } else { propertyInfo.SetValue(obj, value, null); } }