背景

系统的数据导出是一个重要的功能,而且对于excel类型的数据导出需求尤其多,如果系统的数据量不是很大,则无关紧要。但是系统的数据量如果非常巨大,对于导出数据来说就异常困难。

方法一

数据很少的情况下,进行数据导出,可以完全交给前端去做。前端人员可以通过接口获取的数据生成excel进行导出。数据量很少或者只允许用户每次导出很少的数据时,这种做法快速有效,成本很低,而且服务端只会承载数据查询的压力,考虑到数据库主从,这个压力就更小了。

同样,服务端也可以生成excel,通过流的形式进行输出,但是这种做法将压力交给了后端。

方法二(重点)

对于经常需要进行导出的系统来说,一般会搭建一个文件导出服务,这个服务专门为文件导出进行服务。

导出服务,对外提供导出的任务接口,不同业务只需要将需要导出的数据提交给这个服务,这个服务会完成一系列操作。

实现excel导出的步骤如下:

1.定义一个导出服务接口。该接口用于接收导出的数据。对于这个excel导出服务来说不应该处理数据,只需要接收即可。

 /*** 通用excel导出* * @param list 需要导出的数据明细* @param model 数据对象(生成表头)* @param taskName 任务的名称* @param <T>*/default <T> void export(List<T> list, Class model, String taskName) {throw new UnsupportedOperationException();}

2.创建实现类。这里将整个流程划分成4步:

a.创建导出任务。(该任务是为了在excel处理完成后,提供数据给前端进行展示,提供下载链接等信息。)

b.生成excel文件。需要看下面注意事项

c.上传至阿里云。(其它OSS也可,自己搭建的文件服务器也可)

d.更新导出任务。

注意:在服务端生成excel是一个耗内存和磁盘的操作,所以我们需要尽可能的保证excel不能太大。这就意味着在接收数据的时候最好限制条目数,该限制方法可以在调用方处理,也可以在导出的内部处理。事例代码中没有显示处理这一问题。提供以下参考:使用了google的算法。

List<T> partition = null;

if (!CollectionUtils.isEmpty(数据集合)) {

// 进行数据切割

partition = Lists.partition(数据集合, 5000);

}

完整代码如下:

public interface ExcelExportService {

/**

* 通用excel导出

*

* @param list 需要导出的数据明细

* @param model 数据对象

* @param taskName 任务的名称

* @param <T>

*/

default <T> void export(List<T> list, Class model, String taskName) {

throw new UnsupportedOperationException();

}

}

@Service
@Slf4j
public class ExcelExportServiceImpl implements ExcelExportService {@Autowiredprivate TaskMapper taskMapper;@Autowiredprivate ExcelFactory excelFactory;@Resourceprivate ThreadPoolTaskExecutor threadPool;@Overridepublic <T> void export(List<T> list, Class model, String taskName) {threadPool.execute(new Runnable() {@Overridepublic void run() {// 1.创建导出任务Task task = createTask(taskName);// 2.生成excel文件ByteArrayOutputStream out = generateFile(list, model);// 3.上传至阿里云String key = uploadToOSS(out, taskName + ".xls");// 4.更新导出任务updateTask(task.getId(), key);}});}/*** @Author      xuhongchang* @Date        1/3/22  3:00 PM* @Describetion 创建导出任务*/private Task createTask(String taskName) {Task task = new Task();task.setName(taskName);task.setState(TaskEnum.ING.getValue());task.setGmtCreated(new Date());task.setDownloadCount(0);taskMapper.insertSelective(task);return task;}/*** @Author      xuhongchang* @Date        1/3/22  3:30 PM* @Describetion 生成文件*/public <T> ByteArrayOutputStream generateFile(List<T> dataList, Class model) {ByteArrayOutputStream out = new ByteArrayOutputStream();try {excelFactory.createExportExcel().writeExcel(out, dataList, model);} catch (Exception e) {log.error("生成文件时报错:{}", e);}return out;}/**** @Author      xuhongchang* @Date        1/3/22  3:30 PM* @Describetion 上传文件*/private String uploadToOSS(ByteArrayOutputStream out, String filename) {String endpoint = "XXXX";String accessKeyId = "XXXX";String accessKeySecret = "XXXX";String bucketName = "xhc-test-01";String dir = "fileCenter/";OSS ossClient = null;PutObjectResult result = null;String key = dir + filename;try {// 创建OSSClient实例。ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);result = ossClient.putObject(bucketName, key, new ByteArrayInputStream(out.toByteArray()));log.info("上传返回结果: {}", result);} catch (OSSException e) {e.printStackTrace();} finally {// 关闭OSSClient。ossClient.shutdown();return result != null ? key : "";}}private void updateTask(Long id, String url) {Task task = new Task();task.setId(id);task.setState(StringUtils.isBlank(url) ? TaskEnum.FAIL.getValue() : TaskEnum.FINISHED.getValue() );task.setUrl(url);taskMapper.updateByPrimaryKeySelective(task);}}
@Component
public class ExcelFactory<T extends BaseRowModel> {public ExportExcelUtil<T> createExportExcel() {return new ExportExcelUtil<>();}
}
@Component
@Slf4j
public class ExportExcelUtil<T extends BaseRowModel> {public ExportExcelUtil() {}public void createExcel(ByteArrayOutputStream out, List<T> data, List<String> tableHeadList) throws IOException {try {List<List<String>> head = getExcelHead(tableHeadList);ExcelWriter writer = new ExcelWriter(null, out, ExcelTypeEnum.XLSX, true);Table table = new Table(0);table.setHead(head);Sheet sheet1 = new Sheet(1, 0);sheet1.setAutoWidth(true);sheet1.setSheetName("sheet1");writer.write(data, sheet1, table);writer.finish();out.flush();} finally {if (out != null) {out.close();}}}private List<List<String>> getExcelHead(List<String> tableHeadList){List<List<String>> head = new ArrayList<List<String>>();for (String s : tableHeadList) {List<String> column = new ArrayList<String>();column.add(s);head.add(column);}return head;}public void writeExcel(ByteArrayOutputStream out, List<T> data, Class model) throws Exception {WriteSheet writeSheet = new WriteSheet();writeSheet.setSheetName("sheet1");writeSheet.setSheetNo(1);EasyExcel.write(out, model).build().write(data, writeSheet).finish();out.flush();}}
@Slf4j
@Configuration
public class ThreadPoolConfiguration {@Bean("threadPool")public ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(32);// 设置最大线程数executor.setMaxPoolSize(128);// 设置队列容量executor.setQueueCapacity(1000);// 设置线程活跃时间(秒)executor.setKeepAliveSeconds(60);// 设置默认线程名称executor.setThreadNamePrefix("业务线程-");// 设置拒绝策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);return executor;}
}

导出的对象表头设置,导出的中model参数,可以这样设置

/*** 用户名称*/
@ColumnWidth(35)
@ExcelProperty(value = "用户名称", index = 0)
private String userName;/*** 年龄*/
@ColumnWidth(35)
@ExcelProperty(value = "年龄", index = 1)
private Integer age;/*** 地址*/
@ColumnWidth(35)
@ExcelProperty(value = "地址", index = 2)
private String address;

嗯,结束啦!!!

解决系统在大数据情况下如何导出文件(附代码)相关推荐

  1. 前端大数据情况下热力图工具heatmap.js的妙用

    不说废话!直接上场景,例如: 当我们下载APP时,一般会浏览APP的介绍页面,而且肯定会有点击操作,根据某部分或者某个点在这个页面点击的次数,生成对应的点击范围热力图,从而达到反映用户操作行为的功能: ...

  2. 对于大数据大流量情况下微软架构的水平扩展的遐想(瞎想)

    最近回顾SAAS的书籍,书中的扩展架构都有点让我痴迷,但书中介绍的都是以Java,Apache,JBoss,Hadloop等技术实现负载均衡,大数据处理,对于微软架构并未提及,所以让我陷入无限遐想,夜 ...

  3. 大数据智能下数据脱敏的思考

    大数据时代下,海量数据中蕴藏的价值得以挖掘,但也带来隐私信息与关键性敏感数据保护方面的困难.数据脱敏技术是解决这一问题的重要手段之一.传统的脱敏方法人工干预大,配置成本高,对用户的专业素养要求高. 为 ...

  4. 一招教你解决大数据量下的各种报表使用问题

    在我们日常制作报表分析过程中,总会遇到各种问题.比如,报表底层数据日益增多.报表加载超慢,这些情况该怎么解决? 数据库是最常见的能处理大数据的计算方案,而永洪能利用数据库来完成数据计算.但是,有些报表 ...

  5. ElasticSearch面试 - es 在数据量很大的情况下如何提高查询效率啊?

    面试题 es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊? 面试官心理分析 这个问题是肯定要问的,说白了,就是看你有没有实际干过 es,因为啥?其实 es 性能并没有你想象中那么好的.很多时 ...

  6. ES 在数据量很大的情况下如何提高查询效率

    如果面试的时候碰到这样一个面试题:ES 在数据量很大的情况下(数十亿级别)如何提高查询效率? 这个问题说白了,就是看你有没有实际用过 ES,因为啥?其实 ES 性能并没有你想象中那么好的. 很多时候数 ...

  7. ElasticSearch在数据量很大的情况下如何提高查询效率

    目录: 一. es 在数据量很大的情况下(数十亿级别)如何提高查询效率? 二. 数据预热 三. 冷热分离 四. document 模型设计 五. 分页性能优化 一. es 在数据量很大的情况下(数十亿 ...

  8. 大数据背景下知识产权侵权行为网络异化与解决思路 —— 以著作权间接侵权为视角...

    一.大数据对知识产权的影响 (一)大数据对于知识产权的促进作用 互联网的发展壮大为智力成果的传播提供了一个全新的方式,即网络传播方式.相对于传统传播方式,网络传播方式几乎为零成本,因此,网络技术的出现 ...

  9. 独家 | Michael I.Jordan:大数据时代下的安全实时决策堆栈与增强学习(视频+精华笔记)

    金秋九月,2017国际大数据产业技术创新高峰论坛暨大数据系统软件国家工程实验室第一次会议盛大开幕,大数据系统软件国家工程实验室作为大数据系统软件技术研发与工程化的国家级创新平台,将通过大数据系统软件技 ...

最新文章

  1. xshell连接不了服务器显示22端口,win10安装redis,xshell无法连接22端口
  2. Oracle查看用户权限
  3. linux打印机添加命令,Linux Shell脚本系列教程(二):终端打印命令详解
  4. matlab中的图像,MATLAB中图像的基本操作
  5. 运用alarm系统调用检测网络是否断开
  6. python3程序转python2_python2到python3代码转化:2to3
  7. 8张图带你轻松温习Java知识
  8. leetcode 872. 叶子相似的树(dfs)
  9. 机器学习hierarchical clustering_材料学+AI:非监督学习预测新型固态锂离子导体材料...
  10. 福一中招聘计算机教师,2017福建福州一中招聘拟聘公示
  11. 网络协议 反扒机制 fidder 抓包工具
  12. c语言输入y循环n结束,大佬们帮帮忙 帮我改改 怎样能在输入Y后 再次进行for循环...
  13. linux DISPLAY变量
  14. 系统学习NLP(十五)--seq2seq
  15. HTTP协议,到底是什么鬼?
  16. C#+ArcEgine开发(2)添加shp和lyr文件
  17. 异常篇 之 记录一次因“MIUI 优化”引发的无奈。。。
  18. php sql多字段求和,JSP_sql实现多字段求和并查询,下面就sql多字段求和并作为sql - phpStudy...
  19. Wattagio for Mac(电池管理)
  20. 创业教父YC创始人Paul Graham就很烦鼓动年轻创业的

热门文章

  1. 洛谷 P4147 玉蟾宫 题解【悬线dp】
  2. DTE和DCE的区别下:配置串口链路通信
  3. 【CCD图像检测】1:图像检测概述
  4. 健身-胸-背-肩-腿-核心锻炼方法
  5. 微型计算机主板usb电源损坏,电脑主板usb不供电的原因及解决方法
  6. Excel数据比对-批量数据比对
  7. android 无线显示功能,华为手机的无线显示功能在哪,怎么使用?
  8. npi阶段是什么意思_NPI全过程各阶段定义-特性-要点
  9. 亏损、亏损、亏损,在线旅游如何打破魔咒?
  10. 共建音视频技术生态,腾讯云成国内首家直播+点播全线支持AV1视频处理业务公有云