基于DotNetCoreNPOI封装特性通用导出excel
基于DotNetCoreNPOI封装特性通用导出excel
目前根据项目中的要求,支持列名定义,列索引排序,行合并单元格,EXCEL单元格的格式也是随着数据的类型做对应的调整。
效果图:
调用方式
可以看到时非常容易的能够导出数据
// 你的需要导出的数据集合,这里的DownloadResponse就是你自己的数据集合
List<DownloadResponse> dataList = GetDownloadList(data);
var workbook = new XSSFWorkbook();
#region 表格自定义样式
var cellStyle = workbook.CreateCellStyle();
cellStyle.VerticalAlignment = VerticalAlignment.Center;
cellStyle.Alignment = HorizontalAlignment.Center;
var sheet = workbook.CreateSheet("Sheet1");
#endregion
#region 赋值
sheet.SetValue(PropertyHelper.GetPropertyGetters(dataList), workbook);
#endregion
#if DEBUG
string path = Path.Combine(@"D:\", $"{Guid.NewGuid()}.xlsx");
// 输出 Exce 文件
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
workbook.Write(fs);
}
#endif
public class DownloadResponse
{
/// <summary>
/// 第一个参数:列名
/// 第二个参数:索引(顺序)
/// 第三个参数:是否合并单元格
/// 后期可以添加一些样式,比如宽度,颜色等,暂时先这样吧
/// </summary>
[Excel("Customs Area", 0, true)]
public string? CustomsArea { get; set; }
[Excel("Vender", 1, true)]
public string? VendorCode { get; set; }
}
实现代码
public static class PropertyHelper
{
/// <summary>
/// 获取RemarkAttribute的值,并按index正序排序。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dataList"></param>
/// <returns></returns>
public static Dictionary<int, List<PropertyGetterInfo>> GetPropertyGetters<T>(List<T> dataList)
{
var propertyGetters = GetExcelPropertyGetters<T>();
var values = new Dictionary<int, List<PropertyGetterInfo>>();
int rowIndex = 0;
foreach (var response in dataList)
{
foreach (var getter in propertyGetters)
{
string propertyName = getter.Key;
var attr = getter.Value.Attribute;
if (attr != null)
{
var value = getter.Value.Getter(response) as PropertyGetterInfo;
if (!values.TryGetValue(rowIndex, out var list))
{
list = new List<PropertyGetterInfo>();
}
list.Add(value);
values[rowIndex] = list;
}
}
rowIndex++;
}
return values;
}
/// <summary>
/// 获取ExcelAttribute的值。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Dictionary<string, PropertyGetterInfo<T>> GetExcelPropertyGetters<T>()
{
var result = new Dictionary<string, PropertyGetterInfo<T>>();
var properties = (from property in typeof(T).GetProperties()
//where Attribute.IsDefined(property, typeof(RemarkAttribute))
orderby ((ExcelAttribute)property
.GetCustomAttributes(typeof(ExcelAttribute), false)
.Single()).Index
select property).ToArray();
foreach (var prop in properties)
{
var attr = prop.GetCustomAttribute<ExcelAttribute>();
if (attr != null)
{
var getter = CreateGetter<T>(prop);
result[prop.Name] = new PropertyGetterInfo<T>
{
Attribute = attr,
Getter = getter
};
}
}
return result;
}
private static Func<T, PropertyGetterInfo> CreateGetter<T>(PropertyInfo prop)
{
var instance = Expression.Parameter(typeof(T), "instance");
var propertyAccess = Expression.Property(instance, prop);
var castToObject = Expression.Convert(propertyAccess, typeof(object));
var lambdaBody = Expression.MemberInit(
Expression.New(typeof(PropertyGetterInfo)),
Expression.Bind(
typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.Description)),
Expression.Constant(prop.GetCustomAttribute<ExcelAttribute>()?.Description ?? string.Empty)
),
Expression.Bind(
typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.Index)),
Expression.Constant(prop.GetCustomAttribute<ExcelAttribute>()?.Index ?? 0)
),
Expression.Bind(
typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.IsMerge)),
Expression.Constant(prop.GetCustomAttribute<ExcelAttribute>()?.IsMerge ?? false)
),
Expression.Bind(
typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.Value)),
Expression.TypeAs(castToObject, typeof(object))
),
Expression.Bind(
typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.ValueType)),
Expression.Constant(prop.PropertyType.FullName)
)
);
var lambda = Expression.Lambda<Func<T, PropertyGetterInfo>>(lambdaBody, instance);
return lambda.Compile();
}
}
public class PropertyGetterInfo
{
public string Description { get; set; }
public int Index { get; set; }
public bool IsMerge { get; set; }
public object? Value { get; set; }
public string ValueType { get; set; }
}
public class PropertyGetterInfo<T>
{
public ExcelAttribute? Attribute { get; set; }
public Func<T, object?> Getter { get; set; }
}
public class ExcelAttribute : Attribute
{
/// <summary>
/// 列描述
/// </summary>
private string _description;
/// <summary>
/// 列索引
/// </summary>
private int _index;
/// <summary>
/// 是否合并
/// </summary>
private bool _isMerge;
public ExcelAttribute(string desc)
{
_description = desc;
}
public ExcelAttribute(string desc, int index)
{
_description = desc;
_index = index;
}
public ExcelAttribute(string desc, int index, bool isMerge)
{
_description = desc;
_index = index;
_isMerge = isMerge;
}
public string Description
{
get
{
return _description;
}
}
public int Index
{
get
{
return _index;
}
}
public bool IsMerge
{
get
{
return _isMerge;
}
}
}
public static class ExcelHelper
{
static readonly string? _intType = typeof(int).FullName;
static readonly string? _intNullType = typeof(int?).FullName;
static readonly string? _longType = typeof(long).FullName;
static readonly string? _longNullType = typeof(long?).FullName;
static readonly string? _doubleType = typeof(double).FullName;
static readonly string? _doubleNullType = typeof(double?).FullName;
static readonly string? _decimalType = typeof(decimal).FullName;
static readonly string? _decimalNullType = typeof(decimal?).FullName;
static readonly string? _stringType = typeof(string).FullName;
static readonly string? _dateTimeType = typeof(DateTime).FullName;
static readonly string? _dateTimeNullType = typeof(DateTime?).FullName;
static readonly string? _boolType = typeof(bool).FullName;
static readonly string? _boolNullType = typeof(bool?).FullName;
static readonly string? _guidType = typeof(Guid).FullName;
static readonly string? _guidNullType = typeof(Guid?).FullName;
public static void SetValue(this ISheet sheet, Dictionary<int, List<PropertyGetterInfo>> propertyGetters, XSSFWorkbook workbook)
{
bool isHead = true;
int sheetRowIndex = 0;
for (int i = 0; i < propertyGetters.Count; i++)
{
var item = propertyGetters[i];
// 创建表头
if (isHead)
{
var headerRow = sheet.CreateRow(sheetRowIndex);
for (int j = 0; j < item.Count; j++)
{
headerRow.CreateCell(j).SetCellValue(item[j].Description);
}
isHead = false;
i--;
continue;
}
// 创建行
sheetRowIndex++;
var row = sheet.CreateRow(sheetRowIndex);
for (int k = 0; k < item.Count; k++)
{
var thisValue = item[k];
var cell = row.CreateCell(thisValue.Index);
if (thisValue.Value == null)
{
cell.SetCellType(CellType.String);
cell.SetCellValue(string.Empty);
}
if (thisValue.Value != null && thisValue.ValueType == _stringType)
{
cell.SetCellType(CellType.String);
cell.SetCellValue(thisValue.Value?.ToString());
}
// 数值类型
else if (thisValue.Value != null && (thisValue.ValueType == _intNullType
|| thisValue.ValueType == _intType
|| thisValue.ValueType == _decimalNullType
|| thisValue.ValueType == _decimalType
|| thisValue.ValueType == _longNullType
|| thisValue.ValueType == _longType
|| thisValue.ValueType == _doubleType
|| thisValue.ValueType == _doubleNullType
))
{
cell.SetCellType(CellType.Numeric);
double.TryParse(thisValue.Value?.ToString(), out double value);
cell.SetCellValue(value);
}
// 时间类型
else if (thisValue.Value != null && (thisValue.ValueType == _dateTimeNullType
|| thisValue.ValueType == _dateTimeType))
{
DateTime.TryParse(thisValue.Value?.ToString(), out var value);
// 时间类型比较特殊,需要设置特定的单元格样式
var style = workbook.CreateCellStyle();
cell.SetCellValue(value.ToOADate());
style = workbook.CreateCellStyle();
style.DataFormat = HSSFDataFormat.GetBuiltinFormat("m/d/yy");
cell.CellStyle = style;
}
// bool类型
else if (thisValue.Value != null && (thisValue.ValueType == _boolNullType
|| thisValue.ValueType == _boolType))
{
cell.SetCellType(CellType.Boolean);
bool.TryParse(thisValue.Value?.ToString(), out bool value);
cell.SetCellValue(value);
}
// 合并单元格
if (thisValue.IsMerge && thisValue.Value != null)
{
int nextIndex = i + 1;
if (nextIndex >= propertyGetters.Count)
{
continue;
}
var nextValue = propertyGetters[nextIndex];
var e = nextValue.FirstOrDefault(x => x.Description == thisValue.Description && (x.Value?.Equals(thisValue.Value) ?? false));
if (e != null)
{
// 合并当前行和下一行
var range = new CellRangeAddress(sheetRowIndex, sheetRowIndex + 1, e.Index, e.Index);
sheet.AddMergedRegion(range);
}
}
}
}
}
}
基于DotNetCoreNPOI封装特性通用导出excel的更多相关文章
- (gridcontrol等)通用导出excel z
关于DevExpress Winform 的所有可打印控件的导出excel 的通用方法,并且解决DevExpress控件自带的方法存在的缺陷问题 1.解决GridControl自带方法不能导出图片: ...
- Java基于注解和反射导入导出Excel
代码地址如下:http://www.demodashi.com/demo/11995.html 1. 构建项目 使用Spring Boot快速构建一个Web工程,并导入与操作Excel相关的POI包以 ...
- 基于 POI 封装 ExcelUtil 精简的 Excel 导入导出
注 本文是使用 org.apache.poi 进行一次简单的封装,适用于大部分 excel 导入导出功能.过程中可能会用到反射,如若有对于性能有极致强迫症的同学,看看就好. 序 由于 poi 本身只是 ...
- POI通用导出Excel数据(包括样式设计)
前言 前一段时间我写过通用的导入Excel,前几天也写了导出pdf格式的,还有我之前搞得导出Word,我在之前的博客也都介绍了导出和导入是一个道理,无非是一个获取一个是赋值.昨天有一位同仁看了我的Ex ...
- 通用导出excel
循环导出所有行和列 def export_excel(table_name): host,user,passwd,db='192.168.0.12','root','myjcyf','us_sys' ...
- 基于Vue + axios + WebApi + NPOI导出Excel文件
一.前言 项目中前端采用的Element UI 框架, 远程数据请求,使用的是axios,后端接口框架采用的asp.net webapi,数据导出成Excel采用NPOI组件.其业务场景,主要是列表页 ...
- 通过注解实现通用导出Excel
Javaweb开发中数据的导入导出很常见,每次我们都需要写很多代码,所以我就在想能不能写一些通用的方法,之前已经在网上 整理过一些通用的方法,最近在网上看到一位牛人封装的更加简介,自己拿过来整理了一下 ...
- 【ITOO 1】将List数据导出Excel表
需求描述:在课表导入的时候,首先给用户提供模板(excel),然后将用户填写好的数据读取到list集合中.再进行判空处赋值处理,以及去重处理.这篇博客,主要介绍读取excel表和导出excel表的方法 ...
- JAVA实现导出excel功能,封装通用导出工具类
引入maven <!--excel导出--> <dependency> <groupId>net.sourceforge.jexcelapi</groupId ...
- C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序
C#中缓存的使用 缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可: <%@ Outp ...
随机推荐
- FCC 中级算法题 Arguments Optional
Arguments Optional 创建一个计算两个参数之和的 function.如果只有一个参数,则返回一个 function,该 function 请求一个参数然后返回求和的结果. 例如,add ...
- centos7离线安装软件和软件包组
需求: 在一个只有内网的服务器中安装某些需要进行源码编译的软件,并且该软件具有大量的依赖,最坑的是服务器只安装了基本的软件,现在需要手动将Development Tools软件包组安装到该服务器,然后 ...
- MySQL代替in之临时表
如果我们正常的使用IN去查询 SELECT * FROM a JOIN b ON a.id = b.id WHERE b.tag_id IN (1,2,3,4,5,6) 这种因为in里面的参数是连续的 ...
- spacy词向量
spaCy能够比较两个对象,并预测它们的相似程度. 预测相似性对于构建推荐系统或标记重复项很有用. 例如,您可以建议与当前正在查看的用户内容相似的用户内容,或者将支持凭单标记为与现有内容非常相似的副本 ...
- nextcloud file location
- 用猿大师办公助手已经在Chrome网页中打开了Office Word,再用桌面Office打开其他Word打不开怎么办?
我们发现用猿大师办公助手在Chrome网页中已经打开了Word文档,但是再用本地的Word打开其他文档,却直接显示在网页中了,本地打不开Word怎么办? 猿大师办公助手默认新打开文件是在内嵌网页off ...
- 7. 基础增删改 - 创建管理员用Model-Drive App管理后台信息 - 在Model-Driven App中创建视图
当我们创建完Model-Driven之后,就可以在里面创建我们所需要的视图,视图一般分为三类: 个人:根据自己的个人需求创建个人视图,只有创建者和其分享的人才能查看这些视图. 公共:可以根据团体需 ...
- vue-print-nb的应用
1.cnpm i vue-print-nb 2.触发事件:v-print="printObj" 3.触发的是个对象: printObj:{ id: ...
- obs推流核心流程分析
前置步骤和录屏是一样的,见我的上一篇文章 https://www.cnblogs.com/billin/p/17219558.html bool obs_output_actual_start(obs ...
- 依图在实时音视频中语音处理的挑战丨RTC Dev Meetup
前言 「语音处理」是实时互动领域中非常重要的一个场景,在声网发起的「RTC Dev Meetup丨语音处理在实时互动领域的技术实践和应用」 活动中,来自百度.寰宇科技和依图的技术专家,围绕该话题进行了 ...