在做系统的时候,很多时候信息量太大,这时候就需要进行Excel表格信息的导入和导出,今天就来给大家说一下我使用Excel表格信息导入和导出的心得。
1:首先需要在前端显示界面View视图中添加导入Excel和导出Excel按钮:
@using (Html.BeginForm()) { <div class="options"> <input type="button" id="importexcel" name="importexcel" class="k-button" value="@T("从Excel表导入数据")" /> <input type="submit" name="exportexcel-all" class="k-button" value="@T("导出到Excel")" /> </div> }
这里注意,导出Excel是通过获取当下的表单的方式来导出数据的。
2:然后为导入Excel添加function:
<script type="text/javascript"> $(document).ready(function () { $("#importexcel").click(function (e) { e.preventDefault(); var window = $("#importexcel-window");//点击后弹出的操作界面 if (!window.data("kendoWindow")) { window.kendoWindow({ modal: true, width: "400px", title: "@T("从Excel表导入数据")", actions: ["Close"] }); } window.data('kendoWindow').center().open(); }); }); </script>
3:添加点击事件后弹出来的操作界面(importexcel-window):
<div id="importexcel-window" style="display:none;"> @using (Html.BeginForm("ImportExcel", "Family", FormMethod.Post, new { enctype = "multipart/form-data" })) //这里"Family"是控制器的名称 { //"ImportExcel"是控制器中相应方法名称 @Html.AntiForgeryToken() <table style="text-align:left;"> <tr> <td> @T("Excel文件"): </td> <td> <input type="file" id="importexcelfile" name="importexcelfile" /> </td> </tr> <tr> <td colspan="2"> <input type="submit" class="k-button" value="@T("导入数据")" /> </td> </tr> </table> } </div>
4:在控制器端添加导入Excel和导出Excel方法:
(1)导入Excel
[HttpPost] public ActionResult ImportExcel() { if (_workContext.CurrentVendor != null) return AccessDeniedView(); try { var file = Request.Files["importexcelfile"]; if (file != null && file.ContentLength > 0) { _importManager.ImportFamiliesFromXlsx(file.InputStream); } else { ErrorNotification(_localizationService.GetResource("Admin.Common.UploadFile")); return RedirectToAction("GetFamilyListInfo"); } SuccessNotification(_localizationService.GetResource("导入成功")); return RedirectToAction("GetFamilyListInfo"); } catch (Exception exc) { ErrorNotification(exc); return RedirectToAction("GetFamilyListInfo"); } }
这里面 _importManager.ImportFamiliesFromXlsx(file.InputStream) 中_importManager是实例化接口并调用接口中的方法ImportFamiliesFromXlsx()
添加成员变量_importManager:private readonly IImportManager _importManager;
接口IImportManager :
public partial interface IImportManager { /// <summary> /// Import products from XLSX file /// </summary> /// <param name="stream">Stream</param> void ImportFamiliesFromXlsx(Stream stream); }
接口方法的实现:
public partial class ImportManager : IImportManager { public void ImportFamiliesFromXlsx(Stream stream) { using (var xlPackage = new ExcelPackage(stream)) { //得到第一个表的工作簿 var worksheet = xlPackage.Workbook.Worksheets.FirstOrDefault(); if (worksheet == null) throw new NopException("No worksheet found");
//列的属性 var properties = new[] { "户主姓名", }; int iRow = 2;//行 while (true) { bool allColumnsAreEmpty = true; if (worksheet.Cells[iRow, 2].Value != null && !String.IsNullOrEmpty(worksheet.Cells[iRow, 2].Value.ToString())) { allColumnsAreEmpty = false; } if (allColumnsAreEmpty) break; string Name = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "户主姓名")].Value);
//这里主要说明一下在进行相应属性值获取的时候最好跟上面设置列的属性值的顺序一样,为后面进行代码审查的时候节省时间,同时这里面设置的字符串"户主姓名"要与设置列属性的值一样 var group = _groupService.GetAllGroups().FirstOrDefault(m => m.Name == groupExcel.Trim() && m.Village.Name == villageExcel.Trim());//这里如果有表跟表之间的关系的时候需要进行链接查询来获得外键值,否则没有导航就会导入失败,就比如一个村子下面有很多个组,每个组下面又有很多的家庭,这里的_groupService.GetAllGroups()就是进行查询. if (group == null) { break; } var family = _familyService.GetAllFamilies().FirstOrDefault(f => f.IDcardnumber == IDcardnumber);//这里的_family.GetAllFamilies()是得到全部的家庭. bool newFamily = false; if (family == null) { family = new Family(); newFamily = true; } family.Name = Name; family.GroupId = group.Id;//这里组的id值就是我们所需要的外键的值 if (newFamily) { _familyService.InsertFamily(family); } else { _familyService.UpdateFamily(family); } //next product iRow++; } } } }
这样就可以通过Excel表格数据进行数据的导入了
(2)将数据导出到Excel表格:
进行导出时与进行导入时的步骤大庭相径,不同的是一些接口的调用
[HttpPost, ActionName("GetFamilyListInfo")]//这里注意这里的ActionName是显示信息列表对应的视图的方法,同时也是导入功能和导出功能所在的视图的方法. [FormValueRequired("exportexcel-all")]//这里面的值就是前端传回来的"导出Excel"按钮的name的值 public ActionResult ExportExcelAll(FamilyModel model) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers)) return AccessDeniedView(); var familys = _familyService.GetAllFamilies();//这里是得到全部家庭的信息 try { byte[] bytes; using (var stream = new MemoryStream()) { _exportManager.ExportFamiliesToXlsx(stream, familys); bytes = stream.ToArray(); } return File(bytes, "text/xls", "familys.xlsx"); } catch (Exception exc) { ErrorNotification(exc); return RedirectToAction("GetFamilyListInfo"); } }
同样的这里面的_exportManager.ExportFamiliesToXlsx(stream, familys)是实现导出Excel方法的接口并调用方法ExportFamiliesToXlsx()
添加成员变量_exportManager:private readonly IExportManager _exportManager;
IExportManager 接口:
public partial interface IExportManager { /// <summary> /// Export family list to XLSX /// </summary> /// <param name="stream">Stream</param> /// <param name="families">Customers</param> void ExportFamiliesToXlsx(Stream stream, IQueryable<Family> families);//这里的Family是对应数据库的类 }
IExportManager 接口实现:
public partial class ExportManager : IExportManager { /// <summary> /// Export family list to XLSX /// </summary> /// <param name="stream">Stream</param> /// <param name="families">Families</param> public virtual void ExportFamiliesToXlsx(Stream stream, IQueryable<Family> families) { if (stream == null) { throw new ArgumentNullException("stream"); } using (var xlPackage = new ExcelPackage(stream)) { //处理现有的工作表 var worksheet = xlPackage.Workbook.Worksheets.Add("Families");
//设置列属性 var properties = new[] { "户主姓名", "村", "组", }; for (int i = 0; i < properties.Length; i++) { worksheet.Cells[1, i + 1].Value = properties[i];//进行对比赋值 worksheet.Cells[1, i + 1].Style.Fill.PatternType = ExcelFillStyle.Solid;//固体填充样式 worksheet.Cells[1, i + 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228));//背景颜色 worksheet.Cells[1, i + 1].Style.Font.Bold = true;//字体样式,加粗 } int row = 2; foreach (var family in families.ToList())//这里需要注意,这里我们对查询出的全部家庭信息进行ToList(),因为前面我们传参数的时候用的是IQueryable<>,如果传参的时候用的就是IList<>则不需要进行转换.在这里我在应用的时候遇到了问题,在用IQueryable<>时,进行连接查询是会出空值异常的,显示找不到相应的村或者组. { int col = 1; worksheet.Cells[row, col].Value = family.Name; col++; worksheet.Cells[row, col].Value = family.Group.Village.Name; col++; worksheet.Cells[row, col].Value = family.Group.Name; col++;
//这里注意,一定要保证此处设置表格里面的值的时候的顺序一定要与设置列的属性的顺序一样. row++; } xlPackage.Save(); } } }
这样就可以进行数据的导出了。