一、用PHPExcel导出表格。
先看导出类代码,网上也有很多类似代码。
构造方法:
public function __construct(){
class_exists('PHPExcel') || require_once EXTEND_PATH."PHPExcel/Classes/PHPExcel.php";
// 设置导出缓存
$cacheMethod = \PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp;
$cacheSettings = array('memoryCacheSize' => '16MB');
\PHPExcel_Settings::setCacheStorageMethod($cacheMethod,$cacheSettings);
$excelObj = new \PHPExcel();
$this->excelObj = $excelObj;
}
导出执行方法:
public function execute(){
$this->check();
//重复调用execute时,删除之前sheet和数据
$activeSheet = $this->excelObj->setActiveSheetIndex(0);
$rowNum = $activeSheet->getHighestDataRow();
if($rowNum > 1){
//取消表格和excel的关联
$this->excelObj->disconnectWorksheets();
$this->excelObj->createSheet(0);
$activeSheet = $this->excelObj->setActiveSheetIndex(0);
}
// 写入表头
// 写入数据
}
我们导出的表格比较简单,只有一个sheet,所以简单粗暴地设置了index=0。一个场景:我要导出大量的订单数据,放在一个表格,会有内存溢出的问题,所以设置为每1000单放在一个表格。每次都设置导出的订单数据,这里有一个问题,其实循环操作的是同一个activeSheet,比如上次设置的sheet数据有1000行,而最后一次订单数据不满1000行只有500行,这时最后一个表格数据还是有1000行,只是后面的500行数据是之前表格的。
这是我选择的处理方式:
1.移除原有sheet,新建一个sheet,这样还是会报内存溢出的错误,不清楚是怎么处理sheet移除的,对象应该还没销毁。
$this->excelObj->removeSheetByIndex(0);
$this->excelObj->createSheet(0);
$activeSheet = $this->excelObj->setActiveSheetIndex(0);
2.每次检查activeSheet有数据的最大行数(空的sheet默认还是有1行),行数大于1的时候,删除所有行。
$activeSheet->remove(1,$rowNum);
以为这样就解决了,后来发现这个remove方法根本没有任何效果。
3.尝试取消所有单元格和activeSheet的关联,向下面这样,结果报错了。
$activeSheet->disconnectCells();
4.尝试取消activeSheet和excel对象的关联,新建一个sheet。这次可以正常导出多个表格,而且数据是正确的。
$this->excelObj->disconnectWorksheets();
$this->excelObj->createSheet(0);
$activeSheet = $this->excelObj->setActiveSheetIndex(0);
二、下载文件的过程
要导出订单数据,之前一直是生成excel表格和下载在一起处理的。这样在订单数量少的时候没什么问题,几乎点下下载,文件也就跟着下载了。但是数据多的时候,要等很久,用户有可能还会不停点几下。后来改成点击按钮,异步请求服务器生成订单文件,生成完成后,告诉浏览器文件的路径,然后再由浏览器请求文件。
这样做有几个好处:
1.给用户提示。生成文件和下载放一起的话,服务器是没办法和用户有什么交互,因为常见的下载方式,就是将a标签的href设置为后台的一个处理方法,或者用js写个方法设置windows.location.href=url这样,下载就完全交给浏览器处理了。前端无法知道什么时候开始下载,这就无法在用户点击链接或按钮到开始下载文件之前,给用户提示,因为我们的文件是需要实时生成的,需要时间,这段时间要防止用户重复点击,更重要的是给用户提示,您想要的操作已经在执行了,耐心等待就好了。
2.分担服务器压力。生成文件和下载分离,其实下载文件处理的内容比较少。
3.功能更清晰。生成文件和下载分开处理,这中间有可以和浏览器交互的节点,生成文件开始,生成文件成功或失败;后台也可以有在生成文件和下载文件的代码中增加其他处理逻辑。
三、生成的临时文件保存在服务器
生成的文件会保存在服务器,需要每个客户点击时,生成不同的文件名,我用了一个生成简单随机字符串的方法,这个有很多。另外,可以用计划任务定期清理临时文件。