技术点:

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导出等等,还有现有的代码可能不够完善,看到的多多提下宝贵意见吧

最新文章

  1. jsp前端实现分页代码
  2. Linux - 常用Shell命令
  3. 64-who 简明笔记
  4. Solr集群更新配置的方式
  5. 现代JavaScript开发者的工具箱
  6. FL2440驱动添加(5)ADC驱动学习笔记
  7. [C/C++] 各种C/C++编译器对UTF-8源码文件的兼容性测试(VC、GCC、BCB)
  8. 《Entity Framework 6 Recipes》中文翻译——第十二章自定义EntityFramework对象(一)
  9. 循环/loop 结构/structure
  10. Linux apt-get error
  11. SD卡的SPI模式的初始化顺序(转)
  12. 用Web api /Nancy 通过Owin Self Host简易实现一个 Http 服务器
  13. Android系统下用js自定义gesture事件(仿ios实现移动端事件一致)
  14. 阿里巴巴MySQL DBA面试题答案[转]
  15. 每天进步一点点-序列化和反序列(将对象写入硬盘文件and从硬盘文件读出对象)
  16. metasploit-smb扫描获取系统信息
  17. iOS开发-修改UITableViewCell中image和title的位置和大小
  18. 微信小程序实例源码大全2
  19. 使用Apache Bench对网站性能进行测试
  20. hdoj2037 今年暑假不AC

热门文章

  1. 动态导入模块__import__(&quot;str&quot;) importlib标准库
  2. AcWing429. 奖学金
  3. windows使用natapp教程
  4. cmake引入第三方库的debug和release版本之Windows版本
  5. 【LeetCode】333. Largest BST Subtree 解题报告(C++)
  6. 1144 - Ray Gun
  7. 线程 IO流 网络编程 基础总结
  8. StringBoot
  9. Ubuntu mininet+Ryu环境安装
  10. 在linux(deepin)系统下查看当前ip地址与用户名