如何将Laravel Excel导出文件打包为ZIP后实现定时下载
定时Excel导出打包ZIP实现方案
原有逻辑说明
原有定时任务类exportExcelBasedOnID运行流程:
- 任务启动时更新任务状态为处理中
- 读取任务参数生成对应xlsx格式Excel文件
- 将xlsx存入指定存储目录,更新任务状态为完成,记录xlsx文件名供后续下载
改造后完整实现代码
1. 修改定时任务导出类,集成ZIP打包逻辑
核心改动点:
- 生成xlsx文件后,先将文件存入
students子目录 - 初始化ZipArchive创建ZIP包,将xlsx文件加入包内的
students目录 - 打包完成后更新任务记录的产出文件为ZIP包,不再返回xlsx路径
<?php use ZipArchive; use Carbon\Carbon; class exportExcelBasedOnID { public function __construct(ScheduleJob $scheduleJob) { $scheduleJob->processed_at = Carbon::now(); $scheduleJob->processing = true; $scheduleJob->exception = null; $scheduleJob->save(); $this->exportExcels($scheduleJob); } private function exportExcels(ScheduleJob $scheduleJob) { $school = $scheduleJob->school; $payload = unserialize($scheduleJob->payload); $id = $payload['id']; $requestUser = User::where('id', $scheduleJob->user_id)->first(); $students = Excels::where('id', $id); $locale = array_key_exists('locale', $payload) ? $payload['locale'] : \App::getLocale(); // 原有生成$final Excel对象的逻辑保持不变 // a bunch of code to create the file with format called $final // 定义存储根路径 $storageBase = storage_path('app/public/EXCEL/'.$school->school_code); // 定义xlsx存放的students目录,不存在则递归创建 $excelDir = $storageBase.'/students/'; if (!is_dir($excelDir)) { mkdir($excelDir, 0755, true); } // 保存xlsx到students目录 $excelFileName = $name.'.xlsx'; $final->store('xlsx', $excelDir); $excelFullPath = $excelDir.$excelFileName; // 初始化ZIP打包 $zip = new ZipArchive; // ZIP包拼接任务ID避免重名覆盖 $zipFileName = 'students_'.$scheduleJob->id.'.zip'; $zipFullPath = $storageBase.'/'.$zipFileName; // 创建并覆盖同名ZIP文件 if ($zip->open($zipFullPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { // 在ZIP内创建students文件夹 $zip->addEmptyDir('students'); // 将生成的xlsx加入ZIP内的students目录 $zip->addFile($excelFullPath, 'students/'.$excelFileName); // 关闭ZIP句柄完成写入 $zip->close(); // 可选:ZIP生成成功后删除原始xlsx节省存储空间 // unlink($excelFullPath); // 更新任务状态与产出文件 $payload['payload'] = $zipFileName; $scheduleJob->payload = serialize($payload); $scheduleJob->processed_at = Carbon::now(); $scheduleJob->exception = null; $scheduleJob->processing = false; $scheduleJob->save(); } else { // 打包失败记录异常 $scheduleJob->processing = false; $scheduleJob->exception = 'ZIP压缩包创建失败'; $scheduleJob->save(); throw new \Exception('ZIP压缩包创建失败,路径:'.$zipFullPath); } } }
2. 调整下载接口逻辑,适配ZIP包下载
原有export_schedule_zip方法不需要在定时任务中调用,仅作为用户触发下载的接口使用,修改为读取对应任务生成的ZIP包返回即可:
<?php public function export_schedule_zip(School $school, Request $request) { // 根据自身业务逻辑获取对应定时任务记录,拿到存储的ZIP文件名 $scheduleJob = ScheduleJob::where('id', $request->job_id)->firstOrFail(); $payload = unserialize($scheduleJob->payload); $zipFileName = $payload['payload']; $zipFullPath = storage_path('app/public/EXCEL/'.$school->school_code.'/'.$zipFileName); if (!file_exists($zipFullPath)) { abort(404, '导出文件不存在'); } return response()->download($zipFullPath); }
注意事项
- 提前确保
storage/app/public/EXCEL/目录权限为0755,运行PHP进程的用户有读写权限,避免创建目录、写入文件失败 - 如果需要在ZIP中放入多个Excel文件,只需重复调用
$zip->addFile()将文件加入ZIP内的students目录即可 - 定时任务运行在CLI环境下,不要使用相对路径读写文件,统一用
storage_path()、public_path()等助手函数获取绝对路径
内容的提问来源于stack exchange,提问作者apkr x
相关产品推荐
相关产品推荐

