zoukankan      html  css  js  c++  java
  • ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出

    系列目录

    昨天文章太过仓促没有补充导出的示例源码,在者当时弄到到很晚没时间做出导出功能,对阅读理解造成影响,现补充一份示例源码,顺便补充导出的功能说明,望理解

    示例代码下载   https://yunpan.cn/cRTHt5MuKavwH 访问密码 0a47

    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

    准备:

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

    开始:

    1.数据表

    CREATE TABLE [dbo].[Spl_Person](
        [Id] [nvarchar](50) NOT NULL,          --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] NOT NULL,      --创建时间
        [Region] [nvarchar](50) NULL,          --区域
        [Category] [nvarchar](50) NULL,        --类别
     CONSTRAINT [PK_Spl_Person] PRIMARY KEY CLUSTERED 
    (
        [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", "fa fa-level-down", Resource.Import, perm, "Import", true)
        @Html.ToolButton("btnExport", "fa fa-level-up", Resource.Export, perm, "Export", true)

    2.安装LinqToExcel包

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

    3.文件上传

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

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

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

    添加导入前端代码

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

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

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

     保证上传是成功的。

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

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

    在业务层添加以下代码

    using Apps.Common;
    using Apps.Models;
    using Apps.Models.Spl;
    using LinqToExcel;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Apps.Spl.BLL
    {
        public partial class Spl_ProductBLL
        {
            /// <summary>
            /// 校验Excel数据
            /// </summary>
            public bool CheckImportData( string fileName, List<Spl_PersonModel> personList,ref ValidationErrors errors )
            {
              
                var targetFile = new FileInfo(fileName);
    
                if (!targetFile.Exists)
                {
    
                    errors.Add("导入的数据文件不存在");
                    return false;
                }
    
                var excelFile = new ExcelQueryFactory(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");
                //SheetName
                var excelContent = excelFile.Worksheet<Spl_PersonModel>(0);
    
                int rowIndex = 1;
    
                //检查数据正确性
                foreach (var row in excelContent)
                {
                    var errorMessage = new StringBuilder();
                    var person = new Spl_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)
                {
                    return false;
                }
                return true;
            }
    
    
            /// <summary>
            /// 保存数据
            /// </summary>
            public void SaveImportData(IEnumerable<Spl_PersonModel> personList)
            {
                try
                {
                    DBContainer db = new DBContainer();
                    foreach (var model in personList)
                    {
                        Spl_Person entity = new Spl_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 (Exception ex)
                {
                    throw;
                }
            }
        }
    }
    BLL
     public class ValidationErrors : List<ValidationError>
        {
            /// <summary>
            /// 添加错误
            /// </summary>
            /// <param name="errorMessage">信息描述</param>
            public void Add(string errorMessage)
            {
                base.Add(new ValidationError { ErrorMessage = errorMessage });
            }
            /// <summary>
            /// 获取错误集合
            /// </summary>
            public string Error
            {
                get {
                    string error = "";
                    this.All(a => {
                        error += a.ErrorMessage;
                        return true;
                    });
                    return error;
                } 
            }
        }
    ValidationError

    代码包含两个方法

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

    fileName为我们上传的文件。

    personList为承接数据List

    ValidationErrors 错误集合

     public void SaveImportData(IEnumerable<Spl_PersonModel> personList)

    保存数据

    别忘记添加接口

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

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

      public ActionResult Import(string filePath)
            {
                var personList = new List<Spl_PersonModel>();
                 //校验数据is
                bool checkResult = m_BLL.CheckImportData(filePath, personList, ref errors);
                 //校验通过直接保存
                 if (checkResult)
                 {
                     m_BLL.SaveImportData(personList);
                     LogHandler.WriteServiceLog(GetUserId(),"导入成功", "成功", "导入", "Spl_Person");
                     return Json(JsonHandler.CreateMessage(1, Resource.InsertSucceed));
                 }
                 else
                 {
                     string ErrorCol = errors.Error;
                     LogHandler.WriteServiceLog(GetUserId(), ErrorCol, "失败", "导入", "Spl_Person");
                     return Json(JsonHandler.CreateMessage(0, Resource.InsertFail + ErrorCol));
                  }
            
            }

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

     function ImportData()
        {
            $.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包

    在控制器添加以下代码:

       public ActionResult Export()
            {
                var exportSpource = this.GetExportData();
                var dt = JsonConvert.DeserializeObject<DataTable>(exportSpource.ToString());
    
                var exportFileName = string.Concat(
                    "Person",
                    DateTime.Now.ToString("yyyyMMddHHmmss"),
                    ".xlsx");
    
                return new ExportExcelResult
                {
                    SheetName = "人员列表",
                    FileName = exportFileName,
                    ExportData = dt
                };
            }
    
            private JArray GetExportData()
            {
                List<Spl_PersonModel> list = m_BLL.GetList(ref setNoPagerAscById, "");
                JArray jObjects = new JArray();
    
                foreach (var item in list)
                {
                    var jo = new JObject();
                    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);
                }
                return jObjects;
            }

    注意:ExportExcelResult

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

    using ClosedXML.Excel;
    using System;
    using System.Data;
    using System.IO;
    using System.Text;
    using System.Web;
    using System.Web.Mvc;
    
    namespace Apps.Web.Core
    {
        public class ExportExcelResult : ActionResult
        {
            public string SheetName { get; set; }
            public string FileName { get; set; }
            public DataTable ExportData { get; set; }
    
            public ExportExcelResult()
            {
    
            }
    
            public override void ExecuteResult(ControllerContext context)
            {
                if (ExportData == null)
                {
                    throw new InvalidDataException("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>
            /// Exports the excel event handler.
            /// </summary>
            /// <param name="context">The context.</param>
            private void ExportExcelEventHandler(ControllerContext context)
            {
                try
                {
                    var workbook = new XLWorkbook();
    
                    if (this.ExportData != null)
                    {
                        context.HttpContext.Response.Clear();
    
                        // 编码
                        context.HttpContext.Response.ContentEncoding = Encoding.UTF8;
    
                        // 设置网页ContentType
                        context.HttpContext.Response.ContentType =
                            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    
                        // 导出名字
                        var browser = context.HttpContext.Request.Browser.Browser;
                        var exportFileName = 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));
    
                        // Add all DataTables in the DataSet as a worksheets
                        workbook.Worksheets.Add(this.ExportData, this.SheetName);
    
                        using (var memoryStream = new MemoryStream())
                        {
                            workbook.SaveAs(memoryStream);
                            memoryStream.WriteTo(context.HttpContext.Response.OutputStream);
                            memoryStream.Close();
                        }
                    }
                    workbook.Dispose();
                }
                catch (Exception ex)
                {
                    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,导出实际只需要几行代码。哈哈..这是如此的简单。

     return new ExportExcelResult
                {
                    SheetName = "人员列表",
                    FileName = exportFileName,
                    ExportData = dt
                };

    2017-03-08 新增功能:导入前编辑,在导入之前会弹出编辑行的页面,让用户编辑数据或新增数据后决定是否提交

    谢谢大家

  • 相关阅读:
    android gridview画分割线,如图:
    Devexpress 之gridControl
    Devexpress 之gridControl双击行事件
    Devexpress之popupMenu
    Devexpress之dxErrorProvider
    DevExpress之lookupedit
    Devexpress 汉化 代码 zt
    Devexpress之DateEdit学习,可选择日期时 zt
    Devexpress之barManager
    devpress 很好的中文论坛
  • 原文地址:https://www.cnblogs.com/ymnets/p/5621706.html
Copyright © 2011-2022 走看看