前言

  在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 重写ExecuteResultpublic 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();//添加一个sheetISheet 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

   方法是一个String的扩展类,用于将文件名称进行编码,避免出现乱码的情况。

之前测试过程中,在没有使用转码的过程中,发现IE浏览器在下载时,中文名称出现了乱码的情况,其他浏览器正常(这里只测试了IE浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、360浏览器和360极速浏览器)。后来使用了

   HttpContext.Current.Server.UrlEncode(filename)对文件名称进行转码后发现,IE浏览器正常了,除了火狐浏览器,其他浏览器都正常。所有就想到当使用火狐浏览器访问时不对名称进行转码,后来写一个String的扩展方法,方便后期其他下载类使用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;namespace WebSeat.Site.Member.Helper
{/// <summary>/// 说明:String扩展方法/// 创建日期:2016/12/19 9:45:10/// 创建人:曹永承/// </summary>public static class StringHelperExtend{public static string EncodingDownloadFileName(this string filename){if (filename == null){throw new NullReferenceException("filename不能为空");}string agent = HttpContext.Current.Request.Headers["User-Agent"];//如果不是火狐浏览器都进行编码if (agent != null && agent.ToLower().IndexOf("firefox") < 0){return HttpContext.Current.Server.UrlEncode(filename);}return filename;}}
}

六、代码使用

public ActionResult ExportExcel(){//获取数据IList<CityStatics> list = new List<CityStatics>();......ExcelBaseResult<CityStatics> excel = new Excel2003Result<CityStatics>(list, "1.xls", true, "全市各区数据    名称:成都");return excel;}

这样就可以了,看看下载后的excel

补充说明:如果使用gzip压缩方式的,那么文件下载时无法显示文件大小的

C# MVC 自定义ActionResult实现EXCEL下载相关推荐

  1. ASP.NET MVC自定义ActionResult实现文件压缩

    有时候需要将单个或多个文件进行压缩打包后在进行下载,这里我自定义了一个ActionResult,方便进行文件下载 using System; using System.Collections; usi ...

  2. ASP.NET MVC Excel 导入导出 ASP.NET Web API Excel 下载 C# Excel 导入导出

    注意:服务器需要安装office软件 1.Excel导入    提示:未在本地计算机上注册"Microsoft.Jet.OLEDB.4.0"提供程序.               ...

  3. ASP.NET MVC 自定义Razor视图WorkContext

    概述 1.在ASP.NET MVC项目开发的过程中,我们经常需要在cshtml的视图层输出一些公用信息 比如:页面Title.服务器日期时间.页面关键字.关键字描述.系统版本号.资源版本号等 2.普通 ...

  4. .NETFramework-Web.Mvc:ActionResult

    ylbtech-.NETFramework-Web.Mvc:ActionResult 1.程序集 System.Web.Mvc, Version=5.2.3.0, Culture=neutral, P ...

  5. Spring MVC自定义验证注释

    在上一教程中,我展示了如何使用注释来验证表单 . 这对于简单的验证非常有用,但是最终,您需要验证一些现成的注释中没有的自定义规则. 例如,如果您需要根据输入的出生日期来验证用户已超过21岁,或者可能需 ...

  6. 自定义POI的excel工具类-xls-xlsx

    自定义POI的excel工具类-xls-xlsx 使用jdk8(java8)实现Excel导出,随意切换 xls和xlsx.自己只是封装了比较常用方法,07版生成还有bug.ε=(´ο`*)))唉 j ...

  7. 自定义注解导出excel数据

    自定义注解导出excel数据 利用自定义注解方式,对数据列表进行简单的导出操作.即在实体对象的属性域上添加导出标识的注解,在对实体进行导出时,利用自定义注解进行反射的方法,获取实体需要导出的属性及值. ...

  8. java自定义注解实现excel数据导入导出,设置单元格数据验证与生成省市区多列联动效果

    本文通过自定义注解实现excel数据导入导出.以及设置excel文件中列数据验证,即用户在excel文件中输入数据时就可以对数据格式验证是否符合,节省了程序中过多的数据验证操作,注解还额外提供了一系列 ...

  9. MVC自定义AuthorizeAttribute实现权限管理

    [转]MVC自定义AuthorizeAttribute实现权限管理 原文载自:小飞的DD http://www.cnblogs.com/feiDD/articles/2844447.html 网站的权 ...

最新文章

  1. 【指标统计】根据遥控补全遥信
  2. 产品经理面试中那些不忍直视的奇葩题目,面试官你真是够了!
  3. C++菱形继承产生的问题和解决
  4. SQL SERVER读书笔记:nolock
  5. html5进度条插件 传递参数,Html5进度条插件(自写)
  6. OpenCL_Barrier同步
  7. 容器编排技术 -- 使用kubectl实现应用滚动更新
  8. 关于QtCharts中的映射器与模型的使用
  9. 【图像处理基础知识】-傅里叶变换
  10. Spark Streaming之运行原理
  11. 将Docker image push 到azure
  12. L3-025 那就别担心了 (30 分)-PAT 团体程序设计天梯赛 GPLT
  13. 杀死系统中的进程kill和killall命令
  14. 渠道下沉 阿里争食社区经济最后一公里
  15. linux系统安装windows 环境中文字体
  16. 计算机专业英语词库mdx,Mdict词库合集(22本实用词典)
  17. ios 网速监控_iOS 监测网络状态
  18. 反思 大班 快乐的机器人_幼儿园大班教案《机器人》含反思
  19. 0x00007FFE9071C408 (ucrtbase.dll) (xxx.exe 中)处有未经处理的异常: 将一个无效参数传递给了将无效参数视为严重错误的函数。
  20. 视频播放--自动播放

热门文章

  1. solr 3.5 配置及应用(二)
  2. 使用MVC框架中要注意的问题(二):将Model和Controller单独用一个项目设计
  3. hpcp5225设置linux网络,惠普HP color laserjet CP5225打印机驱动
  4. 互联网晚报 | 3月25日 星期五 |​ ​​私募大佬但斌疑似空仓;蔚来和小米汽车拟采用比亚迪电池...
  5. 快手2021服饰品类洞察报告
  6. 2021年中国电子签名行业研究报告
  7. 2020年视频号发展白皮书
  8. 互联网早报 | 10月3日 星期六 | 微信正式上线青少年模式;阿里巴巴首次披露技术研发投入;本田宣布2021赛季后退出F1...
  9. ip地址配置 mongodb_MongoDB安全配置详解
  10. java setquality_Java-在不损失质量的情况下调整图像大小