一、用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.功能更清晰。生成文件和下載分開處理,這中間有可以和瀏覽器交互的節點,生成文件開始,生成文件成功或失敗;後臺也可以有在生成文件和下載文件的代碼中增加其他處理邏輯。
三、生成的臨時文件保存在服務器
生成的文件會保存在服務器,需要每個客戶點擊時,生成不同的文件名,我用了一個生成簡單隨機字符串的方法,這個有很多。另外,可以用計劃任務定期清理臨時文件。