系列目录

前言:

导入导出实在多例子,很多成熟的组建都分装了导入和导出,这一节演示利用LinqToExcel组件对Excel的导入,这个是一个极其简单的例子。

我并不是说导入的简单。而是LinqToExcel让我们对Excel操作更加简单!

最后我们将利用ClosedXML输出Excel。这个比现流行NPOI与EPPlus更加优秀的组件,以Open XML SDK为基础,所以只支持xlsx,不支持xls格式(现阶段谁没有个office2007以上版本)

他导出的Excel根据官方描述,兼容性远超同行对手

如果你不是使用本架构只看2,3,4点,使用BLL层的代码,这同样适用你的MVC程序

知识点:

  • LinqToExcel组件读取Excel文件
  • ClosedXML组件输出Excel

准备:

  1. 一张演示的数据库表
  2. 安装LinqToExcel NuGet包
  3. 文件上传样例
  4. CloseXML导出Excel

开始:

1.数据表

  1. CREATE TABLE [dbo].[Spl_Person](
  2. [Id] [nvarchar](50) NOT NULL, --ID
  3. [Name] [nvarchar](50) NULL, --姓名
  4. [Sex] [nchar](10) NULL, --性别
  5. [Age] [int] NULL, --年龄
  6. [IDCard] [nvarchar](50) NULL, --IDCard
  7. [Phone] [nvarchar](50) NULL, --电话
  8. [Email] [nvarchar](200) NULL, --邮件
  9. [Address] [nvarchar](300) NULL, --地址
  10. [CreateTime] [datetime] NOT NULL, --创建时间
  11. [Region] [nvarchar](50) NULL, --区域
  12. [Category] [nvarchar](50) NULL, --类别
  13. CONSTRAINT [PK_Spl_Person] PRIMARY KEY CLUSTERED
  14. (
  15. [Id] ASC
  16. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  17. ) ON [PRIMARY]
  18.  
  19. GO

如何使用这个框架?

按照之前的做法,更新到EF。并利用T4生成DAL,BLL,MODEL。再用代码生成器生成界面复制进解决方案,一步到位

配置好访问地址和权限,直接运行

再手动在工具栏添加导入和导出的按钮(别忘记添加权限)

  1. @Html.ToolButton("btnImport", "fa fa-level-down", Resource.Import, perm, "Import", true)
  2. @Html.ToolButton("btnExport", "fa fa-level-up", Resource.Export, perm, "Export", true)

2.安装LinqToExcel包

因为我们读取Excel放在BLL层,所有在BLL层安装LinqToExcel包

3.文件上传

(这一点简单带过,可以到网上下载上传代码植入到自己系统中)

或者下载第32节的源码 或者下载本节的示例代码都可以

我这里使用普通的form上传功能

添加导入前端代码

  1. <div id="uploadExcel" class="easyui-window" data-options="modal:true,closed:true,minimizable:false,shadow:false">
  2. <form name="form1" method="post" id="form1">
  3. <table>
  4. <tr>
  5. <th style=" padding:20px;">Excel:</th>
  6. <td style=" padding:20px;">
  7. <input name="ExcelPath" type="text" maxlength="" id="txtExcelPath" readonly="readonly" style="width:200px" class="txtInput normal left">
  8. <a href="javascript:$('#FileUpload').trigger('click').void(0);;" class="files">@Resource.Browse</a>
  9. <input class="displaynone" type="file" id="FileUpload" name="FileUpload" onchange="Upload('ExcelFile', 'txtExcelPath', 'FileUpload');">
  10. <span class="uploading">@Resource.Uploading</span>
  11. </td>
  12. </tr>
  13. </table>
  14. <div class="endbtndiv">
  15. <a id="btnSave" href="javascript:ImportData()" class="easyui-linkbutton btns">Save</a>
  16. <a id="btnReturn" href="javascript:$('#uploadExcel').window('close')" class="easyui-linkbutton btnc">Close</a>
  17. </div>
  18. </form>
  19. </div>

导入按钮事件只要弹出上传框就好

  1. $("#btnImport").click(function () {
  2. $("#uploadExcel").window({ title: '@Resource.Import', width: 450, height: 160, iconCls: 'icon-details' }).window('open');
  3. });

保证上传是成功的。

直接查看源码的C#上传代码

-------------------------------------------------------------------------------------------------------上面只是前期的准备工作--------------------------------------------------------------

在业务层添加以下代码

  1. using Apps.Common;
  2. using Apps.Models;
  3. using Apps.Models.Spl;
  4. using LinqToExcel;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11.  
  12. namespace Apps.Spl.BLL
  13. {
  14. public partial class Spl_ProductBLL
  15. {
  16. /// <summary>
  17. /// 校验Excel数据
  18. /// </summary>
  19. public bool CheckImportData( string fileName, List<Spl_PersonModel> personList,ref ValidationErrors errors )
  20. {
  21.  
  22. var targetFile = new FileInfo(fileName);
  23.  
  24. if (!targetFile.Exists)
  25. {
  26.  
  27. errors.Add("导入的数据文件不存在");
  28. return false;
  29. }
  30.  
  31. var excelFile = new ExcelQueryFactory(fileName);
  32.  
  33. //对应列头
  34. excelFile.AddMapping<Spl_PersonModel>(x => x.Name, "Name");
  35. excelFile.AddMapping<Spl_PersonModel>(x => x.Sex, "Sex");
  36. excelFile.AddMapping<Spl_PersonModel>(x => x.Age, "Age");
  37. excelFile.AddMapping<Spl_PersonModel>(x => x.IDCard, "IDCard");
  38. excelFile.AddMapping<Spl_PersonModel>(x => x.Phone, "Phone");
  39. excelFile.AddMapping<Spl_PersonModel>(x => x.Email, "Email");
  40. excelFile.AddMapping<Spl_PersonModel>(x => x.Address, "Address");
  41. excelFile.AddMapping<Spl_PersonModel>(x => x.Region, "Region");
  42. excelFile.AddMapping<Spl_PersonModel>(x => x.Category, "Category");
  43. //SheetName
  44. var excelContent = excelFile.Worksheet<Spl_PersonModel>(0);
  45.  
  46. int rowIndex = 1;
  47.  
  48. //检查数据正确性
  49. foreach (var row in excelContent)
  50. {
  51. var errorMessage = new StringBuilder();
  52. var person = new Spl_PersonModel();
  53.  
  54. person.Id =
  55. person.Name = row.Name;
  56. person.Sex = row.Sex;
  57. person.Age = row.Age;
  58. person.IDCard = row.IDCard;
  59. person.Phone = row.Phone;
  60. person.Email = row.Email;
  61. person.Address = row.Address;
  62. person.Region = row.Region;
  63. person.Category = row.Category;
  64.  
  65. if (string.IsNullOrWhiteSpace(row.Name))
  66. {
  67. errorMessage.Append("Name - 不能为空. ");
  68. }
  69.  
  70. if (string.IsNullOrWhiteSpace(row.IDCard))
  71. {
  72. errorMessage.Append("IDCard - 不能为空. ");
  73. }
  74.  
  75. //=============================================================================
  76. if (errorMessage.Length > 0)
  77. {
  78. errors.Add(string.Format(
  79. "第 {0} 列发现错误:{1}{2}",
  80. rowIndex,
  81. errorMessage,
  82. "<br/>"));
  83. }
  84. personList.Add(person);
  85. rowIndex += 1;
  86. }
  87. if (errors.Count > 0)
  88. {
  89. return false;
  90. }
  91. return true;
  92. }
  93.  
  94. /// <summary>
  95. /// 保存数据
  96. /// </summary>
  97. public void SaveImportData(IEnumerable<Spl_PersonModel> personList)
  98. {
  99. try
  100. {
  101. DBContainer db = new DBContainer();
  102. foreach (var model in personList)
  103. {
  104. Spl_Person entity = new Spl_Person();
  105. entity.Id = ResultHelper.NewId;
  106. entity.Name = model.Name;
  107. entity.Sex = model.Sex;
  108. entity.Age = model.Age;
  109. entity.IDCard = model.IDCard;
  110. entity.Phone = model.Phone;
  111. entity.Email = model.Email;
  112. entity.Address = model.Address;
  113. entity.CreateTime = ResultHelper.NowTime;
  114. entity.Region = model.Region;
  115. entity.Category = model.Category;
  116. db.Spl_Person.Add(entity);
  117. }
  118. db.SaveChanges();
  119. }
  120. catch (Exception ex)
  121. {
  122. throw;
  123. }
  124. }
  125. }
  126. }

BLL

  1. public class ValidationErrors : List<ValidationError>
  2. {
  3. /// <summary>
  4. /// 添加错误
  5. /// </summary>
  6. /// <param name="errorMessage">信息描述</param>
  7. public void Add(string errorMessage)
  8. {
  9. base.Add(new ValidationError { ErrorMessage = errorMessage });
  10. }
  11. /// <summary>
  12. /// 获取错误集合
  13. /// </summary>
  14. public string Error
  15. {
  16. get {
  17. string error = "";
  18. this.All(a => {
  19. error += a.ErrorMessage;
  20. return true;
  21. });
  22. return error;
  23. }
  24. }
  25. }

ValidationError

代码包含两个方法

public bool CheckImportData( string fileName, List<Spl_PersonModel> personList,ValidationErrors errors )

fileName为我们上传的文件。

personList为承接数据List

ValidationErrors 错误集合

public void SaveImportData(IEnumerable<Spl_PersonModel> personList)

保存数据

别忘记添加接口

  1. public partial interface ISpl_PersonBLL
  2. {
  3. bool CheckImportData(string fileName, List<Spl_PersonModel> personList, ref ValidationErrors errors);
  4. void SaveImportData(IEnumerable<Spl_PersonModel> personList);
  5. }

简单明白,直接看代码,不再解析。OK这样控制器就可以直接调用了

  1. public ActionResult Import(string filePath)
  2. {
  3. var personList = new List<Spl_PersonModel>();
  4. //校验数据is
  5. bool checkResult = m_BLL.CheckImportData(filePath, personList, ref errors);
  6. //校验通过直接保存
  7. if (checkResult)
  8. {
  9. m_BLL.SaveImportData(personList);
  10. LogHandler.WriteServiceLog(GetUserId(),"导入成功", "成功", "导入", "Spl_Person");
  11. return Json(JsonHandler.CreateMessage(, Resource.InsertSucceed));
  12. }
  13. else
  14. {
  15. string ErrorCol = errors.Error;
  16. LogHandler.WriteServiceLog(GetUserId(), ErrorCol, "失败", "导入", "Spl_Person");
  17. return Json(JsonHandler.CreateMessage(, Resource.InsertFail + ErrorCol));
  18. }
  19.  
  20. }

最后前端还需要把路径给回来。

  1. function ImportData()
  2. {
  3. $.post("@Url.Action("Import")?filePath=" + $("#txtExcelPath").val(), function (data) {
  4. if (data.type == ) {
  5. $("#List").datagrid('load');
  6. $('#uploadExcel').window('close');
  7. }
  8. $.messageBox5s('@Resource.Tip', data.message);
  9.  
  10. }, "json");
  11. }

OK测试一下!建立一个新的excel格式

一般情况下我们是提供模版给用户下载供用户输入数据,来确保格式的正确性

--------------------------------------------------------------------------------------导出功能------------------------------------------------------------------------------

4.安装ClosedXML NuGet包

在控制器添加以下代码:

  1. public ActionResult Export()
  2. {
  3. var exportSpource = this.GetExportData();
  4. var dt = JsonConvert.DeserializeObject<DataTable>(exportSpource.ToString());
  5.  
  6. var exportFileName = string.Concat(
  7. "Person",
  8. DateTime.Now.ToString("yyyyMMddHHmmss"),
  9. ".xlsx");
  10.  
  11. return new ExportExcelResult
  12. {
  13. SheetName = "人员列表",
  14. FileName = exportFileName,
  15. ExportData = dt
  16. };
  17. }
  18.  
  19. private JArray GetExportData()
  20. {
  21. List<Spl_PersonModel> list = m_BLL.GetList(ref setNoPagerAscById, "");
  22. JArray jObjects = new JArray();
  23.  
  24. foreach (var item in list)
  25. {
  26. var jo = new JObject();
  27. jo.Add("Id", item.Id);
  28. jo.Add("Name", item.Name);
  29. jo.Add("Sex", item.Sex);
  30. jo.Add("Age", item.Age);
  31. jo.Add("IDCard", item.IDCard);
  32. jo.Add("Phone", item.Phone);
  33. jo.Add("Email", item.Email);
  34. jo.Add("Address", item.Address);
  35. jo.Add("CreateTime", item.CreateTime);
  36. jo.Add("Region", item.Region);
  37. jo.Add("Category", item.Category);
  38. jObjects.Add(jo);
  39. }
  40. return jObjects;
  41. }

注意:ExportExcelResult

此类是使用ClosedXML.Excel,已经封装好了。大家直接拿来用就可以。把关注点都放在业务中

  1. using ClosedXML.Excel;
  2. using System;
  3. using System.Data;
  4. using System.IO;
  5. using System.Text;
  6. using System.Web;
  7. using System.Web.Mvc;
  8.  
  9. namespace Apps.Web.Core
  10. {
  11. public class ExportExcelResult : ActionResult
  12. {
  13. public string SheetName { get; set; }
  14. public string FileName { get; set; }
  15. public DataTable ExportData { get; set; }
  16.  
  17. public ExportExcelResult()
  18. {
  19.  
  20. }
  21.  
  22. public override void ExecuteResult(ControllerContext context)
  23. {
  24. if (ExportData == null)
  25. {
  26. throw new InvalidDataException("ExportData");
  27. }
  28. if (string.IsNullOrWhiteSpace(this.SheetName))
  29. {
  30. this.SheetName = "Sheet1";
  31. }
  32. if (string.IsNullOrWhiteSpace(this.FileName))
  33. {
  34. this.FileName = string.Concat(
  35. "ExportData_",
  36. DateTime.Now.ToString("yyyyMMddHHmmss"),
  37. ".xlsx");
  38. }
  39.  
  40. this.ExportExcelEventHandler(context);
  41. }
  42.  
  43. /// <summary>
  44. /// Exports the excel event handler.
  45. /// </summary>
  46. /// <param name="context">The context.</param>
  47. private void ExportExcelEventHandler(ControllerContext context)
  48. {
  49. try
  50. {
  51. var workbook = new XLWorkbook();
  52.  
  53. if (this.ExportData != null)
  54. {
  55. context.HttpContext.Response.Clear();
  56.  
  57. // 编码
  58. context.HttpContext.Response.ContentEncoding = Encoding.UTF8;
  59.  
  60. // 设置网页ContentType
  61. context.HttpContext.Response.ContentType =
  62. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  63.  
  64. // 导出名字
  65. var browser = context.HttpContext.Request.Browser.Browser;
  66. var exportFileName = browser.Equals("Firefox", StringComparison.OrdinalIgnoreCase)
  67. ? this.FileName
  68. : HttpUtility.UrlEncode(this.FileName, Encoding.UTF8);
  69.  
  70. context.HttpContext.Response.AddHeader(
  71. "Content-Disposition",
  72. string.Format("attachment;filename={0}", exportFileName));
  73.  
  74. // Add all DataTables in the DataSet as a worksheets
  75. workbook.Worksheets.Add(this.ExportData, this.SheetName);
  76.  
  77. using (var memoryStream = new MemoryStream())
  78. {
  79. workbook.SaveAs(memoryStream);
  80. memoryStream.WriteTo(context.HttpContext.Response.OutputStream);
  81. memoryStream.Close();
  82. }
  83. }
  84. workbook.Dispose();
  85. }
  86. catch (Exception ex)
  87. {
  88. throw;
  89. }
  90. }
  91. }
  92. }

总结:

本节知识点,全部聚集在CheckImportData方法上。

对应列头是模版xlsx的列头

1.如果模版需要是是中文的,如Name=名字,那么方法应该这么写

excelFile.AddMapping<Spl_PersonModel>(x => x.Name, "名字");

2.导入第几个sheet工作薄可以这么写

我这里写0是指第一个sheet工作薄。可以直接指定工作薄

var excelContent = excelFile.Worksheet<Spl_PersonModel>("Sheet1");

3.检查正确性可以确保数据的来源。可以给出用户正确的修改提示。

4.借助ClosedXML,导出实际只需要几行代码。哈哈..这是如此的简单。

  1. return new ExportExcelResult
  2. {
  3. SheetName = "人员列表",
  4. FileName = exportFileName,
  5. ExportData = dt
  6. };

ASP.NET MVC5+EF6+EasyUI 后台管理系统(87)-MVC Excel导入和导出的更多相关文章

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(转)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 日程管理   http://ww ...

  2. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入

    系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统-WebApi的用法与调试

    1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+Easy ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级

    系统很久没有更新内容了,期待已久的更新在今天发布了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+E ...

  6. ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构

    系列目录 前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多.主要集中增删该查每个模块都有,所以本次是为封装相同接口方法 如果你想了解怎么重构普通的接口DAL层请查 ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(34)-文章发布系统①-简要分析

    系列目录 最新比较闲,为了学习下Android的开发构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(1)-前言与,虽然有点没有目的的学习,但还是了解了Andro ...

  8. ASP.NET MVC5+EF6+EasyUI 后台管理系统(54)-工作流设计-所有流程监控

    系列目录 先补充一个平面化登陆页面代码,自己更换喜欢的颜色背景 @using Apps.Common; @{ Layout = null; } <!DOCTYPE html> <ht ...

  9. ASP.NET MVC5+EF6+EasyUI 后台管理系统(56)-插件---单文件上传与easyui使用fancybox

    系列目录 https://yunpan.cn/cZVeSJ33XSHKZ  访问密码 0fc2 今天整合lightbox插件Fancybox1.3.4,发现1.3.4版本太老了.而目前easyui 1 ...

  10. ASP.NET MVC5+EF6+EasyUI 后台管理系统(38)-Easyui-accordion+tree漂亮的菜单导航

    系列目录 本节主要知识点是easyui 的手风琴加树结构做菜单导航 有园友抱怨原来菜单非常难看,但是基于原有树形无限级别的设计,没有办法只能已树形展示 先来看原来的效果 改变后的效果,当然我已经做好了 ...

随机推荐

  1. 201521123042 《java程序设计》 第八周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. ①泛型定义:泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展, ...

  2. 201521123089《Java程序设计》第6周学习总结

    1. 本周学习总结 2. 书面作业 clone方法1.1 Object对象中的clone方法是被protected修饰,在自定义的类中覆盖clone方法时需要注意什么?                 ...

  3. 201521123104《JAVA程序设计》第三周学习总结

    1. 本周学习总结 2. 书面作业 Q1. 代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...

  4. 201521123004《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 答:思维导图如下: Java中使用try-catch语法处理异常: try { 可能产生异常的代码段 }catch ...

  5. Java: 类继承中 super关键字

    super 关键字的作用有两个: 1)在子类中调用超类的构造器,完成实例域参数的初始化,调用构造器的语句只能作为另一个构造器(通常指的是子类构造器)的第一条语句出现, 2)在子类中调用超类的方法,如: ...

  6. 磁盘管理之inode与block

    索引式文件系统 什么是inode? Inode其实就是索引号,便于我们寻找我们文件所存储的数据块block,索引式文件系统在查找信息,读写操作上都比原来的文件系统要快,我们可以通过inode中记录的b ...

  7. Lucene第一篇【介绍Lucene、快速入门】

    什么是Lucene?? Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引 ...

  8. java-枚举一些字典信息的例子

    一个典型的枚举应用的例子 package opstools.vtm.dictionary.enums; import opstools.framework.view.ResourceValue; /* ...

  9. jmeter 分布式实战

    最近作者在公司部署公司的分布式压力测试情况的时候,遇到了问题,什么问题呢,各种错误,于是大晚上的为了不耽误压测,我们就两个同事两台电脑搞,可是还是不行的呢,我要研究研究这个是什么梗,于是乎,大晚上加班 ...

  10. 黑马程序员Java基础班+就业班课程笔记全发布(持续更新)

    正在黑马学习,整理了一些课程知识点和比较重要的内容分享给大家,也是给自己拓宽一些视野,仅供大家交流学习,大家有什么更好的内容可以发给我 ,现有黑马教程2000G  QQ 1481135711 这是我总 ...