技术点:

1.自定义attribute属性

2.通过反射取类及其属性的attribute属性值

3.NPOI包常用属性及方法(我也仅仅知道用到过的,陌生的要么见名知意,要么百度查)

实现功能点:

List类对象的模板导出,实用场景例子见最后代码块

(emm...还是比较抽象,代码见)

EXCEL导出类DTO超类
public abstract class ExcelSuper
{
// 所有excel导出类DTO必须要继承的方法
// 限制比较弱,主要还是用来区分DTO用在何处
}
定义继承导出类DTO的特性说明类
/// <summary>
/// 导出类 类特性
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ExcelExpClassAttribute : Attribute
{
public ExcelExpClassAttribute(int colSplit, int rowSplit, int leftmostColumn, int topRow)
{
this.colSplit = colSplit;
this.rowSplit = rowSplit;
this.leftmostColumn = leftmostColumn;
this.topRow = topRow;
} /// <summary>
/// 冻结的列数
/// </summary>
public int colSplit { get; set; }
/// <summary>
/// 冻结的行数
/// 只冻结列时为0
/// </summary>
public int rowSplit { get; set; }
/// <summary>
/// 右边区域可见的首列序号,从1开始计算
/// </summary>
public int leftmostColumn { get; set; }
/// <summary>
/// 边区域可见的首行序号,从1开始计算,
/// 只冻结列时为0
/// </summary>
public int topRow { get; set; }
} /// <summary>
/// 导出类 属性特性
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ExcelExpAttribute : Attribute
{
/// <summary>
/// 是否隐藏,与SortIndex搭配使用
/// </summary>
public bool IsHidden { get; set; } = false;
/// <summary>
/// 排序索引(保持连贯性、不可重复)
/// - 对应dataTable的列排序 [0,1...]
/// - 对应Excel的列索引 [0,1...]
/// </summary>
public int SortIndex { get; set; }
/// <summary>
/// Excel列名
/// </summary>
public string ColName { get; set; }
/// <summary>
/// 是否动态列
/// </summary>
public bool IsdynamicColName { get; set; } /// <summary>
/// 是否合并行 -- 预留,后补
/// </summary>
public bool IsRowMerge { get; set; } = false;
/// <summary>
/// 合并行依据 -- 预留,后补
/// </summary>
public string RowMergeBasis { get; set; }
}
Excel帮助类
    /// <summary>
/// Excel帮助类
/// </summary>
public static class ExcelHelper
{
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="workbook"></param>
/// <param name="dtSource"></param>
/// <param name="sheetNum"></param>
/// <param name="useAttributeColName"> 添加一行列名,取类自定义属性列名称:ExcelExpAttribute.ColName</param>
/// <returns></returns>
private static IWorkbook OutputExcel<T>(this IWorkbook workbook, IEnumerable<T> dtSource, int sheetNum, bool useAttributeColName = false)
{
// 读取sheet
ISheet sheet = workbook.GetSheetAt(sheetNum);
int rowIndex = sheet.LastRowNum + 1;// 获取写入行初始值 if (useAttributeColName)
{
// 待补充
} Type objType = typeof(T); // 取类上的自定义特性
object[] objs = objType.GetCustomAttributes(typeof(ExcelExpClassAttribute), true);
foreach (object obj in objs)
{
ExcelExpClassAttribute attr = obj as ExcelExpClassAttribute;
if (attr != null)
{
sheet.CreateFreezePane(attr.colSplit, attr.rowSplit, attr.leftmostColumn, attr.topRow);// 设置冻结行、列
break;
}
} // 循环添加数据
foreach (T item in dtSource)
{
IRow rowi = sheet.CreateRow(rowIndex); // 设置自适应宽度,9为Excel列数,根据需要自已修改
for (int columnNum = 0; columnNum <= rowi.LastCellNum; columnNum++)
{
int columnWidth = sheet.GetColumnWidth(columnNum) / 256; sheet.SetColumnWidth(columnNum, columnWidth * 256);
} // 取属性上的自定义特性
foreach (PropertyInfo propInfo in objType.GetProperties())
{
object[] objAttrs = propInfo.GetCustomAttributes(typeof(ExcelExpAttribute), true);
if (objAttrs.Length > 0)
{
ExcelExpAttribute attr = objAttrs[0] as ExcelExpAttribute;
if (attr != null)
{
if (attr.IsHidden)
continue; int colIndex = attr.SortIndex;
var name = propInfo.Name;// 实例名称
var value = propInfo.GetValue(item);// 实例值 #region 判断值类型并填充
var newCell = rowi.CreateCell(colIndex);
switch (propInfo.PropertyType.ToString())
{
case "System.String"://字符串类型
newCell.SetCellValue(value == null ? "" : value.ToString());
break;
case "System.DateTime"://日期类型
DateTime.TryParse(value.ToString(), out DateTime dateV);
newCell.SetCellValue(dateV);
break;
case "System.Boolean"://布尔型
bool.TryParse(value.ToString(), out bool boolV);
newCell.SetCellValue(boolV);
break;
case "System.Int16"://整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
int.TryParse(value.ToString(), out int intV);
newCell.SetCellValue(intV);
break;
case "System.Decimal"://浮点型
case "System.Double":
double.TryParse(value.ToString(), out double doubV);
newCell.SetCellValue(doubV);
break;
case "System.DBNull"://空值处理
newCell.SetCellValue("");
break;
default:
newCell.SetCellValue("");
break;
}
#endregion
}
}
} rowIndex++;
} return workbook;
} /// <summary>
/// 导出模板Excel
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="iEnumerable">数据源</param>
/// <param name="fileFullPath">文件全路径(包含文件及后缀名)</param>
/// <returns>文件流</returns>
public static MemoryStream ExportToExcel<T>(IEnumerable<T> iEnumerable, string fileFullPath)
where T : ExcelSuper
{
// 打开模板文件并写入
var workbook = GetIWorkbook(fileFullPath, out ExcelTypeEnum type); if (type == ExcelTypeEnum.XLS)
{
workbook = (HSSFWorkbook)workbook.OutputExcel(iEnumerable, 0, false);
}
else
{
workbook = (XSSFWorkbook)workbook.OutputExcel(iEnumerable, 0, false);
} try
{
using (MemoryStream ms = new MemoryStream())
{
workbook.Write(ms);
ms.Flush();
ms.Position = 0; // sheet.Dispose();
// workbook.Dispose();//一般只用写这一个就OK了,他会遍历并释放所有资源,但当前版本有问题所以只释放sheet
return ms;
}
}
catch (Exception ex)
{
throw ex;
} } #region Private method
private static IWorkbook GetIWorkbook(string fileFullPath, out ExcelTypeEnum type)
{
string filename = Path.GetFileNameWithoutExtension(fileFullPath);// 文件名称
string extension = Path.GetExtension(fileFullPath);// 后缀名 带点(.)
try
{
if (!File.Exists(fileFullPath))
{
throw new Exception($"模板:{filename + extension}不存在");
} FileStream fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.ReadWrite);
if (".xls".Equals(extension.ToLower()))
{
type = ExcelTypeEnum.XLS;
return new HSSFWorkbook(fs);// Excel2003以前版本
}
else
{
type = ExcelTypeEnum.XLSX;
return new XSSFWorkbook(fs);// Excel2007后的版本
}
}
catch (Exception ex)
{ throw new Exception("获取文件错误:" + ex);
}
}
#endregion enum ExcelTypeEnum
{
XLS,
XLSX
}
}

这部分要讲的点其实挺多的,关键就是EXCEL导出所用到的数据源是强类型的。

可以看出来list其实是EF的Queryable toList()后的类集合,作为数据源存在;// 比较喜欢强类型,直接点出来的属性让人放心ヾ(•ω•`)o

里面的DTO DesWeeklyReportExcExp继承ExcelSuper,特性分别加在类及属性上。

public class XXXXController : CoreController
{
// 控制器内部 [HttpPost]
public ActionResult export()
{
// 控制器接口
var list = op
.GetPagedQuery(PageModel)
.Select(s => new DesWeeklyReportExcExp
{
col1 = s.Project.ProjName,
col2 = s.ColAttROPDate1?.ToString("yyyy.MM.dd"),
col3 = (s.ColAttROPDate2 == null ? "无" : s.ColAttROPDate2.Value.ToString("yyyy.MM.dd"))
+ "/"
+ (s.ColAttROPDate3 == null ? "无" : s.ColAttROPDate3.Value.ToString("yyyy.MM.dd")),
col4 = s.ColAttROPDate4?.ToString("yyyy.MM.dd")
}).ToList();
string filePath = Server.MapPath("~/download/[这是模板名称].xlsx");
string filename = Path.GetFileNameWithoutExtension(filePath);// 文件名称
string extension = Path.GetExtension(filePath);// 后缀名 带点(.)
string fileDownloadName = filename + extension; var fs = ExcelHelper.ExportToExcel(list, filePath).ToArray();
return File(fs, "application/ms-excel", fileDownloadName);
}
} [ExcelExpClassAttribute(2, 0, 2, 0)]
public class DesWeeklyReportExcExp : ExcelSuper
{
/// <summary>
/// 列1
/// </summary>
[ExcelExp(SortIndex = 0, ColName = "列1")]
public string col1 { get; set; } /// <summary>
/// 列2
/// </summary>
[ExcelExp(SortIndex = 0, ColName = "列2")]
public string col2 { get; set; } /// <summary>
/// 列3
/// </summary>
[ExcelExp(SortIndex = 0, ColName = "列3")]
public string col3 { get; set; } /// <summary>
/// 列4
/// </summary>
[ExcelExp(SortIndex = 0, ColName = "列4")]
public string col4 { get; set; }
}

部分拙见,大部分还需要补充,比如设置合并列,比如数据源支持DataTable导出等等,还有现有的代码可能不够完善,看到的多多提下宝贵意见吧

C# 实现NPOI的Excel导出的更多相关文章

  1. 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)

    并发编程概述   前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...

  2. C#中用NPOI的excel导出

    //机构表导出 private static List<User2> amininf = new BLL.Bll().GetUser2s(); //定义数据源导出对象 #region 导出 ...

  3. PowerBuilder中调用NPOI进行Excel导出格式设置示例

    // 功能 :新建excel带边框的单元格,格式为数字并显示为美元货币 // 参数 :ai_row,行号:ai_col,列号 // 返回值 :true/false // 作者 :潮崖之飔 // 日期 ...

  4. .NET Excel导出方法及其常见问题详解

    摘要:.NET Excel导出方法及其常见问题详解. 一.Excel导出的实现方法 在.net 程序开发中,对于Excel文件的导出我们一共有三种导出方式: 利用文件输出流进行读写操作 这种方式的导出 ...

  5. NPOI操作EXCEL(四)——反射机制批量导出excel文件

    前面我们已经实现了反射机制进行excel表格数据的解析,既然有上传就得有下载,我们再来写一个通用的导出方法,利用反射机制实现对系统所有数据列表的筛选结果导出excel功能. 我们来构想一下这样一个画面 ...

  6. asp.net mvc4 easyui datagrid 增删改查分页 导出 先上传后导入 NPOI批量导入 导出EXCEL

    效果图 数据库代码 create database CardManage use CardManage create table CardManage ( ID ,) primary key, use ...

  7. NPOI实现Excel导入导出

    NPOI实现Excel的导入导出,踩坑若干. Cyan是博主[Soar360]自2014年以来开始编写整理的工具组件,用于解决现实工作中常用且与业务逻辑无关的问题. 什么是NPOI? NPOI 是 P ...

  8. npoi实现数据导出Excel

    npoi     .NET第三方的Office功能组件. 链接地址 http://npoi.codeplex.com/ 引用命名空间 using NPOI.HSSF.UserModel; using ...

  9. ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案 try.dot.net 的正确使用姿势 .Net NPOI 根据excel模板导出excel、直接生成excel .Net NPOI 上传excel文件、提交后台获取excel里的数据

    ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案   ASP.NET Core 从2.2版本开始,采用了一个新的名为Endpoint的路由方案,与原来的方案在使用上差别不 ...

随机推荐

  1. my.ini配置文件内容

    # For advice on how to change settings please see# http://dev.mysql.com/doc/refman/5.6/en/server-con ...

  2. 有时候错误很奇怪啊,Comparator问题

    有时候错误很奇怪啊,Comparator问题,在我的电脑上排序好用,但是在别的电脑上排序不好用, 真奇怪a

  3. jackson-databind-2.2.3.jar,ackson-annotations-2.2.3.jar和jackson-core-2.2.3.jar下载

    jackson包开发下载,包括如下3个jar文件 jackson-databind-2.2.3.jar,还需要jackson-annotations-2.2.3.jar和jackson-core-2. ...

  4. 【LeetCode】1405. 最长快乐字符串 Longest Happy String

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 贪心 日期 题目地址:https://leetcode ...

  5. 【LeetCode】263. Ugly Number 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 除去2,3,5因子 日期 [LeetCode] 题目 ...

  6. 【LeetCode】890. Find and Replace Pattern 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典+set 单字典 日期 题目地址:https:/ ...

  7. 【LeetCode】429. N-ary Tree Level Order Traversal 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:BFS 方法二:DFS 参考资料 日期 题目 ...

  8. anaconda安装PIL

    PIL仅支持到python2.7: Pillow支持Python 3.x: conda install pillow 参考文献: 使用anaconda安装python3版本的PIL_不行不至-CSDN ...

  9. Sublime Text3快速创建HTML5框架

    输入html:5 按tab键即可

  10. 低成本CH7511芯片方案|CH7511电路设计参考|CS5211替代CH7511

    CH7511是主要用于设计eDP转LVDS转换器,怎么样设计一款低成本低BOM简单的DP转LVDS的转接设置,目前有一款可以替代兼容CH7511的方案电路,并且其设计电路整体BOM成本较低,并且设计简 ...