C# MVC 自定义ActionResult实现EXCEL下载

前言

  在WEB中,经常要使用到将数据转换成EXCEL,并进行下载。这里整理资料并封装了一个自定义ActionResult类,便于使用。如果文章对你有帮助,请点个赞。

  话不多少,这里转换EXCEL使用的NPOI。还是用了一下反射的知识,便于识别实体类的一些自定义特性。

一、自定义一个Attribute

using System;

namespace WebSeat.Entity.Member.Attributes
{
    /// <summary>
    /// 说明:Excel属性特性
    /// 创建日期:2016/12/13 14:24:13
    /// 创建人:曹永承
    /// </summary>
    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true), Serializable]
    public class ExcelDataOptionAttribute:Attribute
    {
        /// <summary>
        /// 显示列下标
        /// </summary>
        public ushort ColumnIndex { get; set; }
        /// <summary>
        /// 显示名称
        /// </summary>
        public string DisplayName { get; set; }
        /// <summary>
        /// 列宽
        /// </summary>
        public int ColumnWidth { get; set; }
        /// <summary>
        /// 单元格数据格式
        /// </summary>
        public string Formater { get; set; }
    }

}

该Attribute用于标记到实体对象的属性上,后面通过反射来识别具体的值

二、定义一个实体类

using WebSeat.Entity.Member.Attributes;

namespace WebSeat.Entity.Member.Excel
{
    /// <summary>
    /// 说明:市首页数据统计Excel表格样式
    /// 创建日期:2016/12/13 14:19:27
    /// 创建人:曹永承
    /// </summary>
    public class CityStatics
    {

        [ExcelDataOption(ColumnIndex = 0, DisplayName = "时段",Formater ="@", ColumnWidth = 14)]
        public string DataDuring { get; set; }

        [ExcelDataOption(ColumnIndex =1,DisplayName ="城市",ColumnWidth =14)]
        public string City { get; set; }

        [ExcelDataOption(ColumnIndex = 2, DisplayName = "登录人数", ColumnWidth = 12)]
        public int StudentLoginedCount { get; set; }

        [ExcelDataOption(ColumnIndex = 3,DisplayName ="登录次数", ColumnWidth = 12)]
        public int StudentLoginTimes { get; set; }

        [ExcelDataOption(ColumnIndex = 4,DisplayName ="登录率",Formater ="0.00%", ColumnWidth = 12)]
        public decimal StudentLoginRatio { get; set; }

        [ExcelDataOption(ColumnIndex = 5,DisplayName ="学习节数", ColumnWidth = 12)]
        public int StudyPeriod { get; set; }

        [ExcelDataOption(ColumnIndex = 6, DisplayName = "学习次数", ColumnWidth = 12)]
        public int StudyTimes { get; set; }

        [ExcelDataOption(ColumnIndex = 7, DisplayName = "人均学习节数(节/人)", Formater = "0.00", ColumnWidth =23)]
        public decimal StudyRatio { get; set; }

        [ExcelDataOption(ColumnIndex = 8, DisplayName = "转化率",Formater = "0.00%", ColumnWidth = 12)]
        public decimal StudyConvertRatio { get; set; }
    }
}

注意:如果属性没有标注ExcelDataOption特性,那么该属性是不会导出到EXCEL中。

   ExcelDataOption中Formater属性,是设置单元格数据类型,这里对于excel中单元格的数据显示个数,例如上面"0.00%"表示以百分百的形式显示数字,且保留2位有效小数

三、定义一个Excel导出父类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using WebSeat.Site.Member.Helper;

namespace WebSeat.Site.Member.CustomResult
{
    /// <summary>
    /// 说明:导出Excel
    /// 创建日期:2016/12/13 13:12:37
    /// 创建人:曹永承
    /// </summary>
    public abstract class ExcelBaseResult<T> :ActionResult
    {
        #region 属性
        /// <summary>
        /// 数据实体
        /// </summary>
        public IList<T> Entity { get; set; }
        /// <summary>
        /// 下载文件名称(不包含扩展名)
        /// </summary>
        public string FileName { get; set; }
        /// <summary>
        /// 是否显示标题
        /// </summary>
        public bool ShowTitle { get; set; }
        /// <summary>
        /// 标题
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// ContentType
        /// </summary>
        public string ContentType { get; set; }
        /// <summary>
        /// 扩展名
        /// </summary>
        public string ExtName { get; set; }
        /// <summary>
        /// 获取下载文件全名
        /// </summary>
        public string FullName { get { return FileName + ExtName; } }

        #endregion

        #region 构造函数
        public ExcelBaseResult(IList<T> entity, string fileName,bool showTitle,string title)
        {
            this.Entity = entity;
            this.FileName = fileName;
            this.ShowTitle = showTitle;
            this.Title = title;
        }
        #endregion

        #region 抽象方法
        public abstract MemoryStream GetExcelStream();
        #endregion

        #region 重写ExecuteResult
        public override void ExecuteResult(ControllerContext context)
        {
            using(MemoryStream ms = GetExcelStream())
            {
                context.HttpContext.Response.AddHeader("Content-Length", ms.Length.ToString());
                context.HttpContext.Response.ContentType = ContentType;
                context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=" + FullName.EncodingDownloadFileName());
                ms.Seek(0, SeekOrigin.Begin);
                Stream output = context.HttpContext.Response.OutputStream;
                byte[] bytes = new byte[1024 * 10];
                int readSize = 0;
                while ((readSize = ms.Read(bytes, 0, bytes.Length)) > 0)
                {
                    output.Write(bytes, 0, readSize);
                    context.HttpContext.Response.Flush();
                }

            }

        }
        #endregion
    }
}

主要因为Excel有不同版本,所有定义了一个父类,其子类只需要实现方法

public abstract MemoryStream GetExcelStream();

四、定义一个子类继承ExcelBaseResult

  这里实现了一个导出.xls格式(2003版本的)到子类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using WebSeat.Entity.Member.Attributes;
using WebSeat.Site.Member.CustomResult;

namespace WebSeat.Site.Member.CustomResult
{
    /// <summary>
    /// 说明:导出成.xls格式的Excel
    /// 创建日期:2016/12/13 13:51:23
    /// 创建人:曹永承
    /// </summary>
    public class Excel2003Result<T>: ExcelBaseResult<T> where T:new()
    {
        public Excel2003Result(IList<T> entity, string fileName,bool showTitle,string title)
            :base(entity,  fileName,  showTitle,  title)
        {
            ContentType = "application/vnd.ms-excel";
            ExtName = ".xls";
        }

        public override MemoryStream GetExcelStream()
        {
            MemoryStream ms = new MemoryStream();
            //获取实体属性
            PropertyInfo[] propertys = typeof(T).GetProperties();
            if (propertys.Count() == 0)
            {
                return ms;
            }
            //创建Excel对象
            IWorkbook book = new HSSFWorkbook();
            //添加一个sheet
            ISheet sheet1 = book.CreateSheet("Sheet1");

            var index = ShowTitle ? 1 : 0;

            //样式设置
            IFont cellfont = book.CreateFont();
            cellfont.FontHeightInPoints = 11;
            cellfont.FontName = "宋体";
            ICellStyle cellStyle = book.CreateCellStyle();
            cellStyle.VerticalAlignment = VerticalAlignment.Center;
            cellStyle.Alignment = HorizontalAlignment.Center;
            cellStyle.SetFont(cellfont);

            IRow rowColumnHead = sheet1.CreateRow(index);
            IDataFormat format = book.CreateDataFormat();
            ushort firstColumn = ushort.MaxValue, lastColumn = ushort.MinValue;  //第一列下标和最后一列下标
            //添加列头
            for (int j = 0; j < propertys.Count(); j++)
            {
                ExcelDataOptionAttribute dataOption = propertys[j].GetCustomAttribute<ExcelDataOptionAttribute>();
                if (dataOption == null)
                {
                    continue;
                }
                IFont font = book.CreateFont();
                font.FontHeightInPoints = 11;
                font.FontName = "宋体";
                ICellStyle style = book.CreateCellStyle();
                style.VerticalAlignment = VerticalAlignment.Center;
                style.Alignment = HorizontalAlignment.Center;
                style.SetFont(font);
                if (!string.IsNullOrWhiteSpace(dataOption.Formater))
                {
                    style.DataFormat = format.GetFormat(dataOption.Formater);
                }

                sheet1.SetDefaultColumnStyle(dataOption.ColumnIndex, style);

                ICell cell = rowColumnHead.CreateCell(dataOption.ColumnIndex);
                cell.SetCellValue(dataOption.DisplayName);

                firstColumn = firstColumn < dataOption.ColumnIndex ? firstColumn : dataOption.ColumnIndex;
                lastColumn = lastColumn > dataOption.ColumnIndex ? lastColumn : dataOption.ColumnIndex;

            }

            index = ShowTitle ? 2 : 1;

            //将各行数据显示出来
            for (int i = 0; i < Entity.Count; i++)
            {
                IRow row = sheet1.CreateRow(i + index);

                //循环各属性,添加列
                for (int j = 0; j < propertys.Count(); j++)
                {
                    ExcelDataOptionAttribute dataOption = propertys[j].GetCustomAttribute<ExcelDataOptionAttribute>();
                    if (dataOption == null)
                    {
                        continue;
                    }

                    ICell cell = row.CreateCell(dataOption.ColumnIndex);

                    //样式设置
                    //cell.CellStyle = cellStyle;
                    if (dataOption.ColumnWidth != 0)
                    {
                        sheet1.SetColumnWidth(dataOption.ColumnIndex, dataOption.ColumnWidth*256);
                    }

                    //根据数据类型判断显示格式
                    if (propertys[j].PropertyType == typeof (int))
                    {
                        cell.SetCellValue((int)propertys[j].GetValue(Entity[i]));
                    }else if (propertys[j].PropertyType == typeof (decimal) || propertys[j].PropertyType == typeof(double) || propertys[j].PropertyType == typeof(float))
                    {
                        cell.SetCellValue(Convert.ToDouble(propertys[j].GetValue(Entity[i])) );
                    }
                    else
                    {
                        cell.SetCellValue(propertys[j].GetValue(Entity[i]).ToString());
                    }
                }
            }

            //将标题合并
            if (ShowTitle)
            {
                IRow rowHead = sheet1.CreateRow(0);
                ICell cellHead = rowHead.CreateCell(firstColumn);
                cellHead.SetCellValue(Title);

                //样式设置
                IFont font = book.CreateFont();
                font.FontHeightInPoints = 14;
                font.IsBold = true;

                ICellStyle style = book.CreateCellStyle();
                style.VerticalAlignment = VerticalAlignment.Center;
                style.Alignment = HorizontalAlignment.Center;
                style.SetFont(font);
                cellHead.CellStyle = style;

                rowHead.HeightInPoints = 20.25f;

                sheet1.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, firstColumn, lastColumn));
            }

            book.Write(ms);
            ms.Seek(0, System.IO.SeekOrigin.Begin);
            return ms;
        }
    }
}

五、下载文件中文名称出现乱码问题

  上面第二步,在Excel导出父类中,有这么一句代码

  context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=" + FullName.EncodingDownloadFileName()); 
  其中EncodingDownloadFileName

  氨基酸掉

时间: 2024-11-01 05:24:55

C# MVC 自定义ActionResult实现EXCEL下载的相关文章

MVC导出数据到EXCEL新方法:将视图或分部视图转换为HTML后再直接返回FileResult

MVC导出数据到EXCEL新方法:将视图或分部视图转换为HTML后再直接返回FileResult 导出EXCEL方法总结:MVC导出数据到EXCEL的方法有很多种,常见的是: 1.采用EXCEL COM组件来动态生成XLS文件并保存到服务器上,然后转到该文件存放路径即可:优点:可设置丰富的EXCEL格式,缺点:需要依赖EXCEL组件,且EXCEL进程在服务器中无法及时关闭,以及服务器上会存留大量的不必要的XLS文件: 2.设置输出头为:application/ms-excel,再输出拼接的HTM

Asp.net MVC 之 ActionResult

Action运行完后,回传的值通过ActionResult 类别或者其衍生的类别操作.ActionResult是一个抽象类,因此,Asp.net MVC 本身就实作了许多不同类型的ActionResult的子类别. ActionResult 子类以及说明: 常用的ViewResult用来回传一个View,即HTML的页面内容: PartialViewResult用来回传一个View,但是这个View是PartialView: RedirectResult用来将网页转向其他的网址: EmptyRe

Mvc自定义验证

假设我们书店需要录入一本书,为了简单的体现我们的自定义验证,我们的实体定义的非常简单,就两个属性,一个名称Name,一个出版社Publisher. public class BookInfo { public string Name { get; set; } public string publisher { get; set; } } Ok,需求有了,实体有了,那么添加我们的控制器和视图.先把代码贴出来.稍后我们在做分析 [HttpGet] public ActionResult Index

MVC自定义编辑视图,DateTime类型属性显示jQuery ui的datapicker

实现的效果为:在编辑视图中,对DateTime类型的属性,显示jQuery UI的datepicker.效果如下: Student.cs public class Student    {        public int Id { get; set; }        public string Name { get; set; }        public DateTime? JoinTime { get; set; }    } HomeController: public class

MVC之ActionResult

一.所有的Controller都继承自System.Web.Mvc.Controller 目前ASP.NET MVC3默认提供了多种ActionResult的实现,在System.Web.Mvc命名空间里. 其中ActionResult是一个抽象类,所有一下的Result都继承自它,因此如果一个Action的返回值是ActionResult的话,可以返回以下任意一种类型的值,但是如果限制死了返回值为以下任意一种Result,则只能够返回指定的类型的数据了. ContentResult Empty

mvc自定义全局异常处理

异常信息处理是任何网站必不可少的一个环节,怎么有效显示,记录,传递异常信息又成为重中之重的问题.本篇将基于上篇介绍的html2cancas截图功能,实现mvc自定义全局异常处理.先看一下最终实现效果:http://yanweidie.myscloud.cn/Home/Index 阅读目录 我理解中好的异常处理 自定义异常处理 问题拓展 总结 回到顶部 我理解中好的异常处理     好的异常信息处理应该具有以下几个优点 显示效果佳,而不是原生黄页 能够从异常中直接分析出异常源 能够记录传递异常信息

.NET MVC之ActionResult

.NET MVC之ActionResult ActionResult是所有Controler返回值的父类.各种结果都是由ActionResult包装后发往客户端的. 继承结构 System.Object System.Web.Mvc.ActionResult System.Web.Mvc.ContentResult System.Web.Mvc.EmptyResult System.Web.Mvc.FileResult System.Web.Mvc.HttpStatusCodeResult Sy

MVC自定义AuthorizeAttribute实现权限管理

[转]MVC自定义AuthorizeAttribute实现权限管理 原文载自:小飞的DD http://www.cnblogs.com/feiDD/articles/2844447.html 网站的权限管理是一个很重要的功能,MVC中怎么实现对于网站的权限管理呢. 在MVC中有一个名为AuthorizeAttribute的类,我们可以创建我们自己的特性 MemberValidationAttribute类,然后继承AuthorizeAttribute类来实现我们自己的网站权限的管理.然后通过将

asp.net mvc 自定义pager封装与优化

asp.net mvc 自定义pager封装与优化 Intro 之前做了一个通用的分页组件,但是有些不足,从翻页事件和分页样式都融合在后台代码中,到翻页事件可以自定义,再到翻页和样式都和代码分离, 自定义分页 pager 越来越容易扩展了. HtmlHelper Pager扩展 Pager V1.0 : 1 /// <summary> 2 /// Pager V1.0 3 /// </summary> 4 /// <param name="helper"&