本文示例代码下载:链接:http://pan.baidu.com/s/1jHBdgCA 密码:hzh7

ps:Vs数据库脚本在解压目录下,修改web.config数据库链接,示例代码包含:导入,导出,上传

前言:

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

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

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

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

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

知识点:

LinqToExcel组件读取Excel文件

ClosedXML组件输出Excel

准备:

一张演示的数据库表

安装LinqToExcel NuGet包

文件上传样例

CloseXML导出Excel

开始:1.数据表

CREATETABLE[dbo].[Spl_Person]([Id][nvarchar](50)NOTNULL,--ID[Name][nvarchar](50)NULL,--姓名[Sex][nchar](10)NULL,--性别[Age][int]NULL,--年龄[IDCard][nvarchar](50)NULL,--IDCard[Phone][nvarchar](50)NULL,--电话[Email][nvarchar](200)NULL,--邮件[Address][nvarchar](300)NULL,--地址[CreateTime][datetime]NOTNULL,--创建时间[Region][nvarchar](50)NULL,--区域[Category][nvarchar](50)NULL,--类别CONSTRAINT[PK_Spl_Person]PRIMARYKEYCLUSTERED([Id]ASC)WITH(PAD_INDEX=OFF,STATISTICS_NORECOMPUTE=OFF,IGNORE_DUP_KEY=OFF,ALLOW_ROW_LOCKS=ON,ALLOW_PAGE_LOCKS=ON)ON[PRIMARY])ON[PRIMARY]GO

如何使用这个框架?

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

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

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

@Html.ToolButton("btnImport","fafa-level-down",Resource.Import,perm,"Import",true)@Html.ToolButton("btnExport","fafa-level-up",Resource.Export,perm,"Export",true)2.安装LinqToExcel包

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

3.文件上传

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

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

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

添加导入前端代码

<divid="uploadExcel"class="easyui-window"data-options="modal:true,closed:true,minimizable:false,shadow:false"><formname="form1"method="post"id="form1"><table><tr><thstyle="padding:20px;">Excel:</th><tdstyle="padding:20px;"><inputname="ExcelPath"type="text"maxlength="255"id="txtExcelPath"readonly="readonly"style="width:200px"class="txtInputnormalleft"><ahref="javascript:$('#FileUpload').trigger('click').void(0);;"class="files">@Resource.Browse</a><inputclass="displaynone"type="file"id="FileUpload"name="FileUpload"onchange="Upload('ExcelFile','txtExcelPath','FileUpload');"><spanclass="uploading">@Resource.Uploading</span></td></tr></table><divclass="endbtndiv"><aid="btnSave"href="javascript:ImportData()"class="easyui-linkbuttonbtns">Save</a><aid="btnReturn"href="javascript:$('#uploadExcel').window('close')"class="easyui-linkbuttonbtnc">Close</a></div></form></div>

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

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

保证上传是成功的。

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

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

在业务层添加以下代码

usingApps.Common;usingApps.Models;usingApps.Models.Spl;usingLinqToExcel;usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceApps.Spl.BLL{publicpartialclassSpl_ProductBLL{///<summary>///校验Excel数据///</summary>publicboolCheckImportData(stringfileName,List<Spl_PersonModel>personList,refValidationErrorserrors){vartargetFile=newFileInfo(fileName);if(!targetFile.Exists){errors.Add("导入的数据文件不存在");returnfalse;}varexcelFile=newExcelQueryFactory(fileName);//对应列头excelFile.AddMapping<Spl_PersonModel>(x=>x.Name,"Name");excelFile.AddMapping<Spl_PersonModel>(x=>x.Sex,"Sex");excelFile.AddMapping<Spl_PersonModel>(x=>x.Age,"Age");excelFile.AddMapping<Spl_PersonModel>(x=>x.IDCard,"IDCard");excelFile.AddMapping<Spl_PersonModel>(x=>x.Phone,"Phone");excelFile.AddMapping<Spl_PersonModel>(x=>x.Email,"Email");excelFile.AddMapping<Spl_PersonModel>(x=>x.Address,"Address");excelFile.AddMapping<Spl_PersonModel>(x=>x.Region,"Region");excelFile.AddMapping<Spl_PersonModel>(x=>x.Category,"Category");//SheetNamevarexcelContent=excelFile.Worksheet<Spl_PersonModel>(0);introwIndex=1;//检查数据正确性foreach(varrowinexcelContent){varerrorMessage=newStringBuilder();varperson=newSpl_PersonModel();person.Id=person.Name=row.Name;person.Sex=row.Sex;person.Age=row.Age;person.IDCard=row.IDCard;person.Phone=row.Phone;person.Email=row.Email;person.Address=row.Address;person.Region=row.Region;person.Category=row.Category;if(string.IsNullOrWhiteSpace(row.Name)){errorMessage.Append("Name-不能为空.");}if(string.IsNullOrWhiteSpace(row.IDCard)){errorMessage.Append("IDCard-不能为空.");}//=============================================================================if(errorMessage.Length>0){errors.Add(string.Format("第{0}列发现错误:{1}{2}",rowIndex,errorMessage,"<br/>"));}personList.Add(person);rowIndex+=1;}if(errors.Count>0){returnfalse;}returntrue;}///<summary>///保存数据///</summary>publicvoidSaveImportData(IEnumerable<Spl_PersonModel>personList){try{DBContainerdb=newDBContainer();foreach(varmodelinpersonList){Spl_Personentity=newSpl_Person();entity.Id=ResultHelper.NewId;entity.Name=model.Name;entity.Sex=model.Sex;entity.Age=model.Age;entity.IDCard=model.IDCard;entity.Phone=model.Phone;entity.Email=model.Email;entity.Address=model.Address;entity.CreateTime=ResultHelper.NowTime;entity.Region=model.Region;entity.Category=model.Category;db.Spl_Person.Add(entity);}db.SaveChanges();}catch(Exceptionex){throw;}}}}

BLL

publicclassValidationErrors:List<ValidationError>{///<summary>///添加错误///</summary>///<paramname="errorMessage">信息描述</param>publicvoidAdd(stringerrorMessage){base.Add(newValidationError{ErrorMessage=errorMessage});}///<summary>///获取错误集合///</summary>publicstringError{get{stringerror="";this.All(a=>{error+=a.ErrorMessage;returntrue;});returnerror;}}}

ValidationError

代码包含两个方法

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

fileName为我们上传的文件。

personList为承接数据List

ValidationErrors 错误集合

public void SaveImportData(IEnumerable<Spl_PersonModel> personList)

保存数据

别忘记添加接口

publicpartialinterfaceISpl_PersonBLL{boolCheckImportData(stringfileName,List<Spl_PersonModel>personList,refValidationErrorserrors);voidSaveImportData(IEnumerable<Spl_PersonModel>personList);}

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

publicActionResultImport(stringfilePath){varpersonList=newList<Spl_PersonModel>();//校验数据isboolcheckResult=m_BLL.CheckImportData(filePath,personList,referrors);//校验通过直接保存if(checkResult){m_BLL.SaveImportData(personList);LogHandler.WriteServiceLog(GetUserId(),"导入成功","成功","导入","Spl_Person");returnJson(JsonHandler.CreateMessage(1,Resource.InsertSucceed));}else{stringErrorCol=errors.Error;LogHandler.WriteServiceLog(GetUserId(),ErrorCol,"失败","导入","Spl_Person");returnJson(JsonHandler.CreateMessage(0,Resource.InsertFail+ErrorCol));}}

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

functionImportData(){$.post("@Url.Action("Import")?filePath="+$("#txtExcelPath").val(),function(data){if(data.type==1){$("#List").datagrid('load');$('#uploadExcel').window('close');}$.messageBox5s('@Resource.Tip',data.message);},"json");}

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

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

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

4.安装ClosedXML NuGet包

在控制器添加以下代码:

publicActionResultExport(){varexportSpource=this.GetExportData();vardt=JsonConvert.DeserializeObject<DataTable>(exportSpource.ToString());varexportFileName=string.Concat("Person",DateTime.Now.ToString("yyyyMMddHHmmss"),".xlsx");returnnewExportExcelResult{SheetName="人员列表",FileName=exportFileName,ExportData=dt};}privateJArrayGetExportData(){List<Spl_PersonModel>list=m_BLL.GetList(refsetNoPagerAscById,"");JArrayjObjects=newJArray();foreach(variteminlist){varjo=newJObject();jo.Add("Id",item.Id);jo.Add("Name",item.Name);jo.Add("Sex",item.Sex);jo.Add("Age",item.Age);jo.Add("IDCard",item.IDCard);jo.Add("Phone",item.Phone);jo.Add("Email",item.Email);jo.Add("Address",item.Address);jo.Add("CreateTime",item.CreateTime);jo.Add("Region",item.Region);jo.Add("Category",item.Category);jObjects.Add(jo);}returnjObjects;}

注意:ExportExcelResult

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

usingClosedXML.Excel;usingSystem;usingSystem.Data;usingSystem.IO;usingSystem.Text;usingSystem.Web;usingSystem.Web.Mvc;namespaceApps.Web.Core{publicclassExportExcelResult:ActionResult{publicstringSheetName{get;set;}publicstringFileName{get;set;}publicDataTableExportData{get;set;}publicExportExcelResult(){}publicoverridevoidExecuteResult(ControllerContextcontext){if(ExportData==null){thrownewInvalidDataException("ExportData");}if(string.IsNullOrWhiteSpace(this.SheetName)){this.SheetName="Sheet1";}if(string.IsNullOrWhiteSpace(this.FileName)){this.FileName=string.Concat("ExportData_",DateTime.Now.ToString("yyyyMMddHHmmss"),".xlsx");}this.ExportExcelEventHandler(context);}///<summary>///Exportstheexceleventhandler.///</summary>///<paramname="context">Thecontext.</param>privatevoidExportExcelEventHandler(ControllerContextcontext){try{varworkbook=newXLWorkbook();if(this.ExportData!=null){context.HttpContext.Response.Clear();//编码context.HttpContext.Response.ContentEncoding=Encoding.UTF8;//设置网页ContentTypecontext.HttpContext.Response.ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";//导出名字varbrowser=context.HttpContext.Request.Browser.Browser;varexportFileName=browser.Equals("Firefox",StringComparison.OrdinalIgnoreCase)?this.FileName:HttpUtility.UrlEncode(this.FileName,Encoding.UTF8);context.HttpContext.Response.AddHeader("Content-Disposition",string.Format("attachment;filename={0}",exportFileName));//AddallDataTablesintheDataSetasaworksheetsworkbook.Worksheets.Add(this.ExportData,this.SheetName);using(varmemoryStream=newMemoryStream()){workbook.SaveAs(memoryStream);memoryStream.WriteTo(context.HttpContext.Response.OutputStream);memoryStream.Close();}}workbook.Dispose();}catch(Exceptionex){throw;}}}}

总结:

本节知识点,全部聚集在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,导出实际只需要几行代码。哈哈..这是如此的简单。

returnnewExportExcelResult{SheetName="人员列表",FileName=exportFileName,ExportData=dt};