Laravel5使用box/spout扩展,大文件导出CSV文件

2023-09-14 21:49:06

一、背景

早期开发的系统,使用laravel框架,版本V5.4,项目经理导出 3 年的数据,由于数据量较大,浏览器卡死。一次性无法导出,某位程序员告知按月去导出,之后在拼凑,这。。搁谁受的了,我担心投诉,加个班优化下。

二、优化方案

  1. 导出数据的Sql,对应创建索引,提高查询速度
  2. 查询结果集使用 chunk() 方法拆分较小集合
  3. 使用box/spout扩展进行导出

三、box/spout扩展安装

由于服务器 PHP 的版本比较老,5.6,box/spout 版本只能安装 v2.7.3,安装流程:

3.1 安装

composer require box/spout:v2.7.3

3.2 使用导出功能

3.2.1 控制器中引入使用到的方法:

use Box\Spout\Common\Type;
use Box\Spout\Writer\WriterFactory;

3.2.2 主要代码示例:

// 实例化类,传递参数:Type::CSV 代表导出 csv 文件,支持 3 种格式
$writer = WriterFactory::create(Type::CSV);

// 浏览器下载方式
// 注意:这里的openToBrowser方法,扩展包源码只传递 1 个 参数,有修改源码,参考四。。
$filename = '文件名称.csv';
$aHeader = [
   'Content-Description: File Transfer',
   'Content-Disposition: attachment; filename=' . $filename,
   'Expires: 0',
   'Cache-Control: must-revalidate',
   'Pragma: public',
];
$writer->openToBrowser($filename, $aHeader);

// 支持文件存储
// 代码:$writer->openToFile("存储路径"); 

// addRow,添加单行 - 表头
$title = ['姓名', '年龄'];
$writer->addRow($title);

// addRow,添加单行 - 示例内容
$content = ['张大胆', 18];
$writer->addRow($content);

// [重要],添加多行内容,使用addRows。查询数据库之后的代码循环拼接内容,示例:
$aDates = [];
$aDates[] = [
		['李胆大', 20],
		['王老五', 25],
		['钱老三', 33],
];
// 假设 - 循环数据库查询结果集,拼多行内容。
foreach ($dbData as $data) 
	$aDatas[] = $data;
}
 // 添加多行
$writer->addRows($aDatas);
// 导出完毕后,关闭Writer对象:
$writer->close();

四、遇到的问题及修改源码包

本地windows环境导出正常,正式 centos 环境导出没有文件名,只有一个csv后缀文件。
怀疑是header的问题,修改源代码,自定义传递 header

修改源码位置:
vendor\box\spout\src\Spout\Writer\WriterInterface接口,30行,增加了 , $headers = []参数

public function openToBrowser($outputFileName, $headers = []);

vendor\box\spout\src\Spout\Writer\AbstractWriter类,134行,增加了 , $headers = []参数

public function openToBrowser($outputFileName, $headers = [])
    {
        $this->outputFilePath = $this->globalFunctionsHelper->basename($outputFileName);

        $this->filePointer = $this->globalFunctionsHelper->fopen('php://output', 'w');
        $this->throwIfFilePointerIsNotAvailable();

        // Clear any previous output (otherwise the generated file will be corrupted)
        // @see https://github.com/box/spout/issues/241
        $this->globalFunctionsHelper->ob_end_clean();

        // Set headers
        $this->globalFunctionsHelper->header('Content-Type: ' . static::$headerContentType);

        /*
         * When forcing the download of a file over SSL,IE8 and lower browsers fail
         * if the Cache-Control and Pragma headers are not set.
         *
         * @see http://support.microsoft.com/KB/323308
         * @see https://github.com/liuggio/ExcelBundle/issues/45
         */

        /*
         * 核心修改代码位置
         */
        foreach ($headers as $header){
            $this->globalFunctionsHelper->header($header);
        }

        $this->openWriter();
        $this->isWriterOpened = true;

        return $this;
    }

五、结果

筛选跨年数据一次性导出,皆大欢喜。

更多推荐

Vue-devTools安装—创建项目方法2 ui创建——Vue指令综合案例——汽车品牌管理

目录项目源代码:一、vue-devTools安装二、案例功能实现1、新建项目(ui创建)2、cnpm导入项目依赖库3、删除不需要的代码结构:4、修改代码结构5、添加汽车品牌插件安装bootstrap的提示功能添加bootstrap样式6、删除汽车品牌7、查询汽车品牌(过滤)项目源代码:Vue指令综合案例——汽车品牌管理

(二十九)大数据实战——kafka集群节点服役与退役案例实战

前言本节内容是关于kafka集群节点的服役与退役,从而实现kafka集群的缩容与扩容。在开始本节内容之前,我们要预先安装好kafka集群,并准备一台空余的服务器用来完成我们扩容与缩容的案例。关于kafka集群的安装内容这里不在赘述,相关内容请查看作者往期博客内容。正文从hadoop103克隆一台空闲服务器hadoop1

QT信号槽实现原理

定义Q_OBJECT宏在宏中声明了几个重要的成员变量及成员函数,包括声明了一个只读的静态成员变量staticMetaObject,以及3个public的成员函数staticconstQMetaObjectstaticMetaObject;virtualconstQMetaObject*metaObject()const

低代码之IVX

低代码之IVX一、如何去分析不同的低代码平台🧝‍♂️1.看自己的网站和平台是不是通过自己的低代码/无代码平台生成的2.生成源代码的能力3.可视化的逻辑编排二、低代码平台未来的发展方向👨‍🌾三、优质低代码平台介绍👨‍💼1.什么是iVX:2.iVX和其它低代码平台的区别上手步骤1.1iVX线上集成环境进入1.2创

python爬虫——爬取豆瓣top250电影数据(适合初学者)

前言:爬取豆瓣top250其实是初学者用于练习和熟悉爬虫技能知识的简单实战项目,通过这个项目,可以让小白对爬虫有一个初步认识,因此,如果你已经接触过爬虫有些时间了,可以跳过该项目,选择更有挑战性的实战项目来提升技能。当然,如果你是小白,这个项目就再适合不过了。那么就让我们开始吧!目录一、实战1.对豆瓣网网站进行Ajax

数据库设计与建模

数据库设计与建模1数据库设计的三范式2数据库建模2.1建模工具2.2使用pd建模1数据库设计的三范式三范式:1.第一范式(1NF):确保每一列的原子性(做到每列不可拆分)2.第二范式(2NF):在第一范式的基础上,非主字段必须依赖于主字段(一个表只做一件事)3.第三范式(3NF):在第二范式的基础上,消除传递依赖反三范

IOS数据管理

在iOS中,没有直接与Android中的SharePreference相对应的概念。而是使用不同的机制来处理应用程序的持久化数据。在iOS中,你可以使用以下几种方法来保存和读取应用程序的数据:UserDefaults(用户默认设置):UserDefaults提供了一种简单的键值存储机制,用于存储应用程序的配置和用户偏好

【Jetpack】Navigation 导航组件 ③ ( 为 Navigation Graph 页面跳转 action 添加跳转动画 )

文章目录一、为NavigationGraph添加跳转动画1、进入NavigationGraph配置的Design模式2、选中action跳转3、为action跳转设置enterAnim进入动画4、为action跳转设置exitAnim退出动画5、通过代码为action跳转设置进入/退出动画6、执行效果代码地址:CSDN

Qt/C++音视频开发54-视频监控控件的极致设计

一、前言跌跌撞撞摸爬滚打一步步迭代完善到今天,这个视频监控控件的设计,在现阶段水平上个人认为是做的最棒的(稍微自恋一下),理论上来说应该可以用5年不用推翻重写,推翻重写当然也是程序员爱干的事情,这个就要考验个人的功底,设计的好框架搭建的好,可以很多年不用变,只需要在现有框架小修小补即可,最多就是继承基类实现一些特殊性的

【机器学习】详解回归(Regression)

文章目录是什么的问题案例说明是什么的问题回归分析(RegressionAnalysis)是研究自变量与因变量之间数量变化关系的一种分析方法,它主要是通过因变量Y与影响它的自变量Xi(i1,2,3…)X_i(i1,2,3…)Xi​(i1,2,3…)之间的回归模型,衡量自变量XiX_iXi​对因变量Y的影响能力的,进而可以

【SpringCloud】微服务技术栈入门1 - 远程服务调用、Eureka以及Ribbon

目录远程服务调用RestTemplateEureka简要概念配置Eureka环境设置EurekaClientEureka服务发现Ribbon工作流程配置与使用Ribbon饥饿加载远程服务调用RestTemplateRestTemplate可以模拟客户端来向另外一个后端执行请求黑马给出的微服务项目中,有两个boot项目,

热文推荐