• 第10章 初识SqlSugarCore之NPOI Excel导出


    当前用于Excel导出常用中间件有:NPOI、 ClosedXML、EPPlus。

        NPOI:如SqlSugarCore一样都是国人的开源中件项目,优点也一样:很多示例程序,容易上手,学习曲线也比较平缓。缺点:很久以前本人就过NPOI实现Excel导出,当时由于Excel程序只能打开,通过NPOI中间件自动生成的“.xls”编码格式的Excel文件,如果通过NPOI中间件自动生成的“.xlsx” 编码格式的Excel文件,则Excel程序将不能打该文件,即NPOI中间件只支持自动生成“.xls” 编码格式的Excel文件,而不支持自动生成“.xlsx” 编码格式,到现在为之只少在导出上NPOI(v2.5.6)中间件依然如故。

    ClosedXML:是在OpenXml规范上开发的,所它天然支持“.xlsx”编码格式的Excel文件。但是这个命名实在让人吐槽,ClosedXML是对Excel文件进行导入/导出,而不是XML文件,不要它所遵循的规范就命名为“ClosedXML”,另外ClosedXML中间件是一个比较新的中间件,当前版本的迭代的速度也比较快。

    EPPlus:功能强大,相对成熟只支持“.xlsx”编码格式的Excel文件的导入/导出,但据说在第4版以后需要购买许可证才能使用(本人未测试,如果有时间会测试,但看到许多开源项目都从EPPlus转到ClosedXML,至具体信息请知道的在评论区留言)

    由于需要剖析1个通过NPOI中间件实现Excel导入/导出操作,所以本章特别讲解NPOI,如果开发者要使用本人的推荐优先级:ClosedXML>EPPlus> NPOI

    1 重构LogicRender\ Index.cshtml

    1.1 添加HTML定义

    <button type="button" id="ResetExam" class="btn btn-secondary  me-4">

                                <i class="fa-solid fa-rotate-right">i>

                                重置

                            button>

                            <div class="btn-group">

                                <button type="button" class="btn btn-success">

                                    <i class="fas fa-download">i>

                                    导出

                                button>

                                <button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">

                                button>

                                <ul class="dropdown-menu">

                                    <li>

                                        <a id="ExportExamToExcel" class="btn mx-auto bg-success text-white bg-opacity-75">

                                            <i class="far fa-file-excel">i>导出所选到Excel

                                        a>

                                    li>

                                    <li>

                                        <a href="/LogicRender/ExportAllExamToExcel" class="btn mx-auto bg-success text-white bg-opacity-75 mt-1">

                                           <i class="far fa-file-excel">i>导出全部到Excel

                                        a>

                                    li>

                                ul>

                            div>

    1.2 添加JavaScript定义

    //把选中的所有考试成绩导出到Excel文件中。

            $("#ExportExamToExcel").on("click", function () {

                var idArray = new Array(); //选中的所有考试成绩的ID数组

                $("[name=checkItem]:checkbox:checked").each(function (index) {

                    idArray.push($(this).val());

                });

                if (idArray.length == 0) {

                    alert("请选择要导出的考试成绩!");

                    return;

                }

                alert("导出考试成绩的编号:" + idArray);

                $.post("/LogicRender/ExportExamToExcelAjax/", { IdArray: idArray }, function (data) {

                    console.log(data.isSuccss);

                    if (data.isSuccss) {

                        var pageIndex = tableModel.page();//当前页页码值,但是DataTables插件的页面是从“0”开始,而不从“1”。

                        $("#example").DataTable().page(pageIndex).draw(false); //刷新当前页;或跳转到指定页。

                        window.open(data.fileRelativePath);

                    }

                    else {

                        alert(data.message);

                    }

                });

            });

    2 重构LogicRenderController

    2.1 通过AJAX调用导出Excel

    /// name="IdArray">数组实例,该实例存储着1/N个整型编号值。

            ///

            /// 【导出所选考试成绩到Excel文件】

            ///

            /// 摘要:

            ///     把所选考试成绩,持久化保存到指定Excel文件中。

            /// 注意:

            ///    该方法通过“FileStream”会将指定Excel文件在服务器端的指定目录(文件夹)中,及其客户端的“下载”目录(文件夹)中各个持久化保存1份。

            ///

            ///

            /// 返回:

            ///     Excel文件持久化操作状态的JSON编码数据。

            ///

            ///

            [HttpPost]

            public async Task ExportExamToExcelAjax(int[] IdArray)

            {

                 //获取所以需要被持久化“考试成绩”的所有实例。

                 ISugarQueryable _examQueryable = _context.SugarScope.Queryable()

                    .Includes(score => score.CourseSingleton)//1层级联

                    .Includes(

                        exam => exam.StudentSingleton,

                        student => student.SpecialtySingleton)//2层级联

                    .Includes(

                        exam => exam.StudentSingleton,

                        student => student.CategorySingleton)//2层级联

                    .Includes(

                        exam => exam.StudentSingleton,

                        student => student.CategorySingleton,

                        category => category.GradeSingleton).OrderBy(exam=>exam.Id);//3层级联

                    List _exportExamList = new List();

                    _exportExamList = await _examQueryable.Where(exam => IdArray.Contains(exam.Id)).ToListAsync();

                    //通过NPOI中间件,创建Excel文件的对象。

                    HSSFWorkbook _excelBook = new HSSFWorkbook();

                    //在当前创建Excel文件,添加一个工作表:“考试成绩”

                    ISheet _examSheet = _excelBook.CreateSheet("考试成绩");

                    //结“考试成绩”工作表添加第一行的头部标题

                    var row1 = _examSheet.CreateRow(0);

                    row1.CreateCell(0).SetCellValue("编号");

                    row1.CreateCell(1).SetCellValue("姓名");

                    row1.CreateCell(2).SetCellValue("学号");

                    row1.CreateCell(3).SetCellValue("专业");

                    row1.CreateCell(4).SetCellValue("年级");

                    row1.CreateCell(5).SetCellValue("班级");

                    row1.CreateCell(6).SetCellValue("试卷名称");

                    row1.CreateCell(7).SetCellValue("课程");

                    row1.CreateCell(8).SetCellValue("成绩");

                    //将数据依次写入 “考试成绩”工作表各个行

                    for (var i = 0; i < _exportExamList.Count; i++)

                    {

                        var rowtemp = _examSheet.CreateRow(i + 1);

                        rowtemp.CreateCell(0).SetCellValue(_exportExamList[i].Id.ToString());

                        rowtemp.CreateCell(1).SetCellValue(_exportExamList[i].StudentSingleton.Name);

                        rowtemp.CreateCell(2).SetCellValue(_exportExamList[i].StudentSingleton.Code);

                        rowtemp.CreateCell(3).SetCellValue(_exportExamList[i].StudentSingleton.SpecialtySingleton.Name);

                        rowtemp.CreateCell(4).SetCellValue(_exportExamList[i].StudentSingleton.CategorySingleton.GradeSingleton.Name);

                        rowtemp.CreateCell(5).SetCellValue(_exportExamList[i].StudentSingleton.CategorySingleton.Name);

                        rowtemp.CreateCell(6).SetCellValue(_exportExamList[i].Name);

                        rowtemp.CreateCell(7).SetCellValue(_exportExamList[i].CourseSingleton.Name);

                        if (_exportExamList[i].Score != null)

                        {

                            rowtemp.CreateCell(8).SetCellValue(_exportExamList[i].Score.ToString());

                        }

                        else

                        {

                            rowtemp.CreateCell(8).SetCellValue(_exportExamList[i].Comment);

                        }

                    }

                    //注意:Excel程序只能打,通过NPOI中间件自动生成的“.xls”格式的Excel文件,如果通过NPOI中间件自动生成的“.xlsx”格式的Excel文件,Excel程序将不能打该文件

                    //即NPOI中间件只支持自动生成“.xls”格式的Excel文件,而不支持自动生成“.xlsx”格式的Excel文件。

                    //Excel导出文件被持久化保存在服务器端目录(文件夹)中的相对路径。

                    string _hostRelativeDirectory = "/Excel导出/" + DateTime.Now.ToString("yyyy-MM-dd") + "/";

                    //当前被持久化保存的Excel文件的文件名。

                    string _excelFileName = "成绩单_选择结果(" + DateTime.Now.ToString("HHmmssfff") + ").xls";

                    string fileRelativePath = _hostRelativeDirectory + _excelFileName;//fileRelativePath变量要回传给:AJax方法。

                    //获取服务器端中当前程序的“wwwroot”目录(文件夹)的绝对路径。

                    string _webRootPath = _webHostEnvironment.WebRootPath;

                    //Excel导出文件被持久化保存在服务器端目录(文件夹)中的绝对路径。

                    string _hostAbsoluteDirectory = _webRootPath + _hostRelativeDirectory;

                    //如果指定绝对路径中没有该目录(文件夹)不存在,则新建该目录(文件夹)。

                    DirectoryInfo _directoryInfo = new DirectoryInfo(_hostAbsoluteDirectory);

                    if (!_directoryInfo.Exists)

                        _directoryInfo.Create();

                    //当前Excel文件被持久化保存的绝对路径。

                    string _fileAbsolutePath = _hostAbsoluteDirectory + _excelFileName;

                    try

                    {

                        // 通过文件流实例,把内存中的数据持久化保存到服务器端的指定目录(文件夹)中,并在持久化完成后,最后通过文件流实例的关闭方法,来自动销毁和释放内存中的数据。

                        FileStream _fileStream = new FileStream(_fileAbsolutePath, FileMode.Create);

                        _excelBook.Write(_fileStream);

                        _fileStream.Flush();

                        _fileStream.Close();

                        return Json(new { isSuccss = true, message = "Excel导出成功", fileRelativePath });

                    }

                    catch (Exception exception)

                    {

                        if (_excelBook != null)

                            _excelBook.Close();

                        if (System.IO.File.Exists(_fileAbsolutePath))

                            System.IO.File.Delete(_fileAbsolutePath);

                        Console.Write(exception.Message);

                        return Json(new { isSuccss = false, message = "Excel导出失败", string.Empty });

                    }

            }

    2.2 通过路由调用导出Excel

    ///

            /// 【导出所选考试成绩到Excel文件】

            ///

            /// 摘要:

            ///     把所有考试成绩,持久化保存到指定Excel文件中。

            /// 注意:

            ///     该方法通过“ControllerBase.File”直接把内存中指定Excel文件持久化保存到客户端的“下载”目录(文件夹)中; 服务器端不在持久化保存该Excel文件。

            ///

            ///

            /// 返回:

            ///    把内存中指定Excel文件持久化保存到客户端的“下载”目录(文件夹)中后,打开。

            ///

            ///

            public async Task ExportAllExamToExcel()

            {

                //获取“考试成绩”的所有实例。

                List _exportExamList = await _context.SugarScope.Queryable()

                    .Includes(score => score.CourseSingleton)//1层级联

                    .Includes(

                        exam => exam.StudentSingleton,

                        student => student.SpecialtySingleton)//2层级联

                     .Includes(

                        exam => exam.StudentSingleton,

                        student => student.CategorySingleton)//2层级联

                    .Includes(

                        exam => exam.StudentSingleton,

                        student => student.CategorySingleton,

                        category => category.GradeSingleton)//3层级联

                    .OrderBy(exam => exam.Id)

                    .ToListAsync();

                //通过NPOI中间件,创建Excel文件的对象。

                HSSFWorkbook _excelBook = new HSSFWorkbook();

                //在当前创建Excel文件,添加一个工作表:“考试成绩”

                ISheet _examSheet = _excelBook.CreateSheet("考试成绩");

                //结“考试成绩”工作表添加第一行的头部标题

                var row1 = _examSheet.CreateRow(0);

                row1.CreateCell(0).SetCellValue("编号");

                row1.CreateCell(1).SetCellValue("姓名");

                row1.CreateCell(2).SetCellValue("学号");

                row1.CreateCell(3).SetCellValue("专业");

                row1.CreateCell(4).SetCellValue("年级");

                row1.CreateCell(5).SetCellValue("班级");

                row1.CreateCell(6).SetCellValue("试卷名称");

                row1.CreateCell(7).SetCellValue("课程");

                row1.CreateCell(8).SetCellValue("成绩");

                //将数据依次写入 “考试成绩”工作表各个行

                for (var i = 0; i < _exportExamList.Count; i++)

                {

                    var rowtemp = _examSheet.CreateRow(i + 1);

                    rowtemp.CreateCell(0).SetCellValue(_exportExamList[i].Id.ToString());

                    rowtemp.CreateCell(1).SetCellValue(_exportExamList[i].StudentSingleton.Name);

                    rowtemp.CreateCell(2).SetCellValue(_exportExamList[i].StudentSingleton.Code);

                    rowtemp.CreateCell(3).SetCellValue(_exportExamList[i].StudentSingleton.SpecialtySingleton.Name);

                    rowtemp.CreateCell(4).SetCellValue(_exportExamList[i].StudentSingleton.CategorySingleton.GradeSingleton.Name);

                    rowtemp.CreateCell(5).SetCellValue(_exportExamList[i].StudentSingleton.CategorySingleton.Name);

                    rowtemp.CreateCell(6).SetCellValue(_exportExamList[i].Name);

                    rowtemp.CreateCell(7).SetCellValue(_exportExamList[i].CourseSingleton.Name);

                    if (_exportExamList[i].Score != null)

                    {

                        rowtemp.CreateCell(8).SetCellValue(_exportExamList[i].Score.ToString());

                    }

                    else

                    {

                        rowtemp.CreateCell(8).SetCellValue(_exportExamList[i].Comment);

                    }

                }

                //注意:Excel程序只能打,通过NPOI中间件自动生成的“.xls”格式的Excel文件,如果通过NPOI中间件自动生成的“.xlsx”格式的Excel文件,Excel程序将不能打该文件

                //即NPOI中间件只支持自动生成“.xls”格式的Excel文件,而不支持自动生成“.xlsx”格式的Excel文件。

                //当前被持久化保存的Excel文件的文件名。

                string _excelFileName = "所有成绩(" + DateTime.Now.ToString("HHmmssfff") + ").xls";

                MemoryStream _memoryStream = new MemoryStream();

                try

                {

                    _excelBook.Write(_memoryStream);

                    byte[] data = _memoryStream.ToArray();

                    

                     //通过“ControllerBase.File”直接把内存中指定Excel文件持久化保存到客户端的“下载”目录(文件夹)中; 服务器端不在持久化保存该Excel文件。

                    return File(data, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", _excelFileName);

                }

                catch (Exception exception)

                {

                    if (_excelBook != null)

                        _excelBook.Close();

                    if (_memoryStream != null)

                    {

                        _memoryStream.Close();

                        _memoryStream.Dispose();

                    }

                    Console.Write(exception.Message);

                    return RedirectToAction("Index");

                }

            }

    对以上功能更为具体实现和注释见:22-10-20-10_SqlSugarAcquaintance(初识SqlSugarCore之NPOI Excel导出)。

  • 相关阅读:
    求解汉诺塔问题【修改版】
    ABC212
    [网络/HTTPS/Java] PKI公钥基础设施体系:数字证书(X.509)、CA机构 | 含:证书管理工具(jdk keytool / openssl)
    解决国外镜像无法访问导致的R包无法安装问题
    动态sql和分页
    电脑系统Windows11安全中心内存完整性打开不了怎么办
    795. 区间子数组个数
    【气动学】基于Matlab模拟各类导弹跟踪
    【前端】Vue+Element UI案例:通用后台管理系统-登陆页面功能:登录权限跳转、路由守卫、退出
    kubernetes快速部署
  • 原文地址:https://blog.csdn.net/zhoujian_911/article/details/127422607