根据数据源自定义字段实现动态导出Excel
前言
最近遇到了一个需求,需要导出各种订单数据,可能是因为懒吧,不想重新写查询然后导出数据;就有了下边的这些操作了。
具体实现方式
1),定义一个泛型类来接收我们要导出的数据源,(需要EPPlus包)代码如下:
1 /// <summary>
2 /// 传入数据,返回Excel流文件
3 /// </summary>
4 /// <typeparam name="T"></typeparam>
5 /// <param name="TSources">数据源</param>
6 /// <param name="sheetName">sheet名字</param>
7 /// <returns></returns>
8 private async Task<MemoryStream> GetExcelMemoryStreams<T>(List<T> TSources, string sheetName = "sheet1")
9 {
10 return await Task.Run(() =>
11 {
12 MemoryStream ms = new MemoryStream();
13 if (TSources.Any())
14 {
15 using (ExcelPackage package = new ExcelPackage())
16 {
17 ExcelWorksheet sheet = package.Workbook.Worksheets.Add(sheetName);
18
19
20 //获取传进来的类型
21 Type type = typeof(T);
22 var propertiesList = type.GetProperties();
23
24 for (int row = 1; row <= TSources.Count() + 1; row++)
25 {
26 var index = 0;
27 for (int cl = 1; cl <= propertiesList.Length; cl++)
28 {
29 //获取备注名字
30 var displayName = propertiesList[cl - 1].GetExportExcelDisplayName();
31 //判断字段是否有自定义属性(ExportExcelColumnAttribute)
32 if (displayName != "false")
33 {
34 index++;
35 if (row == 1) //设置表头
36 sheet.Cells[row, index].Value = displayName;
37 else
38 {
39 //获取字段名字
40 var Name = propertiesList[cl - 1].Name;
41 //获取对应的值
42 var value = TSources[row - 2].GetType().GetProperty(Name)?.GetValue(TSources[row - 2])?.ToString();
43 sheet.Cells[row, index].Value = value;
44 }
45 }
46 }
47 }
48
49 //设置Excel列宽
50 sheet.Cells.AutoFitColumns(1.5);
51
52 package.SaveAs(ms);
53 ms.Position = 0;
54 }
55 }
56 else
57 throw new UserFriendlyException($"{sheetName}暂无数据!");
58
59 return ms;
60 });
61 }
2),定义实体属性标识导出列,代码如下:
1 /// <summary>
2 /// Excel导出用
3 /// </summary>
4 [AttributeUsage(AttributeTargets.Property)]//标记只能用在属性上面
5 public class ExportExcelColumnAttribute : Attribute
6 {
7 private string _Name = null;
8
9 /// <summary>
10 /// 构造涵数传入值
11 /// </summary>
12 /// <param name="Name"></param>
13 public ExportExcelColumnAttribute(string Name)
14 {
15 this._Name = Name;
16 }
17
18 public string GetDisplayName()
19 {
20 return _Name;
21 }
22 }
3),定义获取该属性的备注名(Excel导出列名)方法,代码如下:
1 /// <summary>
2 /// 获取属性设置的导出备注
3 /// </summary>
4 /// <param name="prop"></param>
5 /// <returns></returns>
6 public static string GetExportExcelDisplayName(this PropertyInfo prop)
7 {
8 if (prop.IsDefined(typeof(ExportExcelColumnAttribute), true))
9 {
10 ExportExcelColumnAttribute attribute = (ExportExcelColumnAttribute)prop.GetCustomAttribute(typeof(ExportExcelColumnAttribute), true);
11 return attribute.GetDisplayName();
12 }
13 else
14 {
15 return "false";
16 }
17 }
4),在实体上标注要导出的字段
1 public class GetServerOrderListDto : NullableIdDto<long>
2 {
3 /// <summary>
4 /// 订单编号
5 /// </summary>
6 [ExportExcelColumn("订单编号")]
7 public string OrdernNumber { get; set; }
8
9 /// <summary>
10 /// 赠购单id
11 /// </summary>
12 public long? OrderID { get; set; }
13
14 /// <summary>
15 /// 赠送单号
16 /// </summary>
17 [ExportExcelColumn("赠送单号")]
18 public string ComplimentaryOrderNumber { get; set; }
19 /// <summary>
20 /// 收费单号
21 /// </summary>
22 [ExportExcelColumn("收费单号")]
23 public string AdditionalOrdernNumber { get; set; }
24
25 /// <summary>
26 /// 客户名称
27 /// </summary>
28 [ExportExcelColumn("客户名称")]
29 public string CompanyName { get; set; }
30 }
5),接口服务调用:
6).控制器需要将返回的内存流转化为文件流(FileStreamResult)返回到前端响应。
7).前端js代码
//点击导出按钮
$("#export_excel").click(function () {
var input = {
....
}; const req = new XMLHttpRequest();
req.open('Post', '你的请求地址', true);
req.responseType = 'blob';
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.onload = function () {
const data = req.response;
const blob = new Blob([data]);
let blobUrl = window.URL.createObjectURL(blob);
download(blobUrl, "你要导出的文件名");
};
var str = "";
var keys = Object.keys(input);
$.each(keys, function (idx, val) {
str += `&${val}=${input[val]}`;
});
console.log(str.substring(1, str.length))
req.send(str);
}); function download(blobUrl,fileName) {
const a = document.createElement('a');
a.style.display = 'none';
a.download = fileName;
a.href = blobUrl;
a.click();
document.body.removeChild(a);
}
温馨提示
a),上述第34行 index 作用主要是防止出现空白列,(实体列中不标识某列导出时(如上述实体 赠送订单ID),会显示空白列的问题:如下图情况:);
b),导出列会比较窄,我们需要设置自适应宽度: sheet.Cells.AutoFitColumns(1.5); 调整列宽;
c),返回的内存流 MemoryStream 返回的时候需要将位置至为0(代码中:ms.Position = 0;);因为Read()方法是从当前流的Position属性的位置开始读,这就是为什么很多人测试的时候,刚刚写入内存的数据,Read()方法无法读取到内容的原因,因为刚刚写入内存之后,位置恰好是在最后一位了。Read()方法当然读不到。此方法强大之处在于,你可以从一个内存流中读出你想要的一个片段。
d),using块的 ExcelPackage对象不需要手动释放,因为他继承了IDisposable,在使用完之后会自动释放;如下图:
e),MemoryStream 是一个特例,MemoryStream中没有任何非托管资源,所以它的Dispose不调用也没关系;托管资源.Net会自动回收;
根据数据源自定义字段实现动态导出Excel的更多相关文章
- JavaWeb动态导出Excel可弹出下载
由于项目需求,需要将数据导出成Excel表格,并且可选择导出项,可下载.项目使用的Spring+Mybatis+SpringMVC框架,利用Apache POI导出Excel.POI具体使用请自行百度 ...
- Java 导出EXCEL
1.Apache POI简介 Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程式对Microsoft Office格式档案读和写的功能. .NET的开发人员则 ...
- POI导出EXCEL经典实现
1.Apache POI简介 Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程式对Microsoft Office格式档案读和写的功能. .NET的开发人员则 ...
- struts2中利用POI导出Excel文档并下载
1.项目组负责人让我实现这个接口,因为以前做过类似的,中间并没有遇到什么太困难的事情.其他不说,先上代码: package com.tydic.eshop.action.feedback; impor ...
- Java POI 导出EXCEL经典实现 Java导出Excel
转自http://blog.csdn.net/evangel_z/article/details/7332535 在web开发中,有一个经典的功能,就是数据的导入导出.特别是数据的导出,在生产管理或者 ...
- java中使用poi导出excel表格数据并且可以手动修改导出路径
在我们开发项目中,很多时候会提出这样的需求:将前端的某某数据以excel表格导出,今天就给大家写一个简单的模板. 这里我们选择使用poi导出excel: 第一步:导入需要的jar包到 lib 文件夹下
- EasyUI 如何结合JS导出Excel文件
出处:http://blog.csdn.net/jumtre/article/details/41119991 EasyUI 如何结合JS导出Excel文件 分类: 技术 Javascript jQu ...
- js导出excel:前端当前数据的导出
网上找的库文件,同样做了修改.在导出的时候,有时候数据第一列和最后一列可能是复选框和操作按钮,这个是我们不需要的,加了这个的过滤 //table2excel.js /* * jQuery table2 ...
- POI导出EXCEL经典实现(转)
http://www.cnblogs.com/xwdreamer/archive/2011/07/20/2296975.html 1.Apache POI简介 Apache POI是Apache软件基 ...
随机推荐
- Java文件字节流
//输出和输入流 package com.kangkang.IO; import com.sun.xml.internal.ws.util.xml.CDATA; import java.io.File ...
- 关于 JMeter 5.4.1 的一点记录
APACHE JMeter table { border: 0; border-collapse: collapse; background-color: rgba(255, 245, 218, 1) ...
- (报错解决)Exception encountered during context initialization
转: (报错解决)Exception encountered during context initialization 关键词 JavaEE JavaWeb eclipse XML AspectJ ...
- ElasticSearch(ES)使用Nested结构存储KV及聚合查询
自建博客地址:https://www.bytelife.net,欢迎访问! 本文为博客同步发表文章,为了更好的阅读体验,建议您移步至我的博客 本文作者: Jeffrey 本文链接: https://w ...
- 使用zap接收gin框架默认的日志并配置日志归档
目录 使用zap接收gin框架默认的日志并配置日志归档 gin默认的中间件 基于zap的中间件 在gin项目中使用zap 使用zap接收gin框架默认的日志并配置日志归档 本文介绍了在基于gin框架开 ...
- Java 获取小程序openid(基于SpringBoot)
Java 获取小程序openid(基于SpringBoot) 官方文档 wx.login 1.引入Request封装依赖 <!--Request依赖--> <dependency&g ...
- 推荐一个能让谷歌浏览器变暗色的插件(darkreader)
下载 https://codechina.csdn.net/mirrors/darkreader/darkreader?utm_source=csdn_github_accelerator 安装教程 ...
- 解决新版谷歌浏览器在http请求下无法开启麦克风问题
1.在浏览器地址栏中输入"chrome://flags/#unsafely-treat-insecure-origin-as-secure", 2.将该选项置为Enabled, 3 ...
- FreeBSD NGINX TCP转发
前几天搞转发,研究了下TCP转发,现在记录下来 首先加载模块 注意:这是FreeBSD的位置.并且需要NGINX支持 load_module /usr/local/libexec/nginx/ngx_ ...
- docker+compose+nginx+php
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. 我用docker做什么? 快速搭建开发所需环境,测试实验新 ...