主题
数据导出功能
数据导出功能是后台管理系统的核心需求,CatchAdmin 专业版提供了完整的 Excel 数据导出解决方案。基于 Laravel Excel 进行深度封装,支持简单的数据导出和高性能的大数据量导出。同时集成 xlswriter
扩展,可实现百万级数据导出且内存占用极低
基本使用
CatchAdmin 专业版提供了抽象基础类,继承该类可快速实现 Excel 数据导出功能。以下是用户数据导出的实现示例
php
namespace Modules\User\Export;
// 该类就是基础核心类,通过集成它可以快速实现导出
use Catch\Support\Excel\Export;
class User extends Export
{
// 这里需要设置导出的头信息
protected array $header = [
'id', '昵称', '邮箱', '创建时间'
];
// 实现 array 方法,返回导出的数据
public function array(): array
{
// TODO: Implement array() method.
return \Modules\User\Models\User::query()
->select('id', 'username', 'email', 'created_at')
->without('roles')
->get([
'id', 'username', 'email', 'created_at'
])->toArray();
}
}
只需要轻松的几行代码,便可实现导出 Excel。这只是实现了导出类,那么如何使用呢? 也很简单,例如在 UserController
添加 export 方法,注入导出类
php
public function export(\Modules\User\Export\User $export)
{
return $export->download();
}
直接通过 download
方法实现 excel
的下载。这个看起来似乎还比较繁琐,每次都要写一个导出类。一般平时导出的需求没有这么复杂,那么有没有更加简便的方法?答案是有的。看下面的例子
php
public function export()
{
return User::query()
->select('id', 'username', 'email', 'created_at')
->without('roles')
->get()
->download(['id', '昵称', '邮箱', '创建时间']);
}
CatchAdmin 专业版通过扩展 Laravel Collection 添加 download
方法,无需编写专门的导出类即可快速实现 Excel 数据导出功能。
对于大数据量导出场景,同步导出可能导致请求超时或内存溢出。当需要导出数万条数据且包含复杂计算查询时,虽然可以使用 Laravel Queue,但缺乏任务状态监控和集中管理功能。CatchAdmin 专业版提供了异步任务管理机制,支持导出任务的状态追踪和进度监控
php
<?php
namespace Modules\User\Export;
// 首先这里需要继承 AsyncTaskInterface 接口
use Catch\Contracts\AsyncTaskInterface;
use Catch\Support\Excel\Export;
// 然后引入 AsyncTaskInterface
use Modules\System\Support\Traits\AsyncTaskDispatch;
class User extends Export implements AsyncTaskInterface
{
// 这里 use 它,这样任务就可以变成异步的了
use AsyncTaskDispatch;
protected array $header = [
'id', '昵称', '邮箱', '创建时间'
];
public function array(): array
{
// TODO: Implement array() method.
return \Modules\User\Models\User::query()
->select('id', 'username', 'email', 'created_at')
->without('roles')
->get([
'id', 'username', 'email', 'created_at'
])->toArray();
}
}
好了,任务搞好了,再来看看控制器如何写
php
/**
* @return void
*/
public function export(\Modules\User\Export\User $export)
{
// 控制器就更加简单了,直接 push 推送即可
return $export->push();
}
完成异步任务配置后,需要启动任务调度程序。在 app/Console/Kernel.php
中添加定时任务调度
php
protected function schedule(Schedule $schedule): void
{
$schedule->command('async:task')->everyMinute();
}
异步任务的执行状态、进度信息和详细日志,可在后台管理系统的系统管理/异步任务
模块中实时查看和管理
大数据量导出
Xlswriter
Xlswriter 是高性能的 Excel PHP 扩展,专为大数据量处理优化。
CatchAdmin 专业版对 xlswriter
进行了深度封装,支持百万级数据导出且内存占用极低。通过优化的数据处理机制,可实现大规模数据导出而不会导致内存溢出。由于大数据量导出耗时较长,建议配合异步任务使用
INFO
只支持游标(cursor)查询模式,也就是惰性查询。非惰性会退化成 Laravel Excel 实现
快捷导出
php
// 使用 Xlswriter 进行高性能数据导出
User::query()
->select('id', 'username', 'email', 'created_at')
->cursor() // 使用游标查询,避免内存溢出
->download(['id', '昵称', '邮箱', '创建时间']);
支持游标模式分块导出,进一步优化内存使用
php
// 结合游标查询和分块处理,提升性能
User::query()
->select('id', 'username', 'email', 'created_at')
->cursor() // 游标查询模式
->chunk(5) // 分块处理,每次处理 5 条记录
->download(['id', '昵称', '邮箱', '创建时间']);
单独导出类
也可以写一份单独导出类,可支持异步
php
<?php
namespace Modules\User\Export;
use Catch\Contracts\AsyncTaskInterface;
use Illuminate\Support\LazyCollection;
use Modules\System\Support\Traits\AsyncTaskDispatch;
use Catch\Support\Excel\XlsWriterExport;
class UserXlsWriter extends XlsWriterExport implements AsyncTaskInterface
{
use AsyncTaskDispatch;
protected array $header = [
'id', '昵称', '邮箱', '创建时间',
];
/**
* 支持全部导出,也支持惰性导出,大数据量一定要用惰性导出
*/
public function array(): array|LazyCollection
{
// TODO: Implement array() method.
return User::query()
->select('id', 'username', 'email', 'created_at')
->limit(100)
->cursor()
->chunk(10);
}
/**
* 设置样式
*/
public function formats(): array
{
$handle = $this->excelObject->getHandle();
$format = new \Vtiful\Kernel\Format($handle);
$boldStyle = $format->bold()->fontSize(10)->toResource();
return [
['A1', 10, $boldStyle]
];
}
/**
* 编辑密码保护,注意不是文档密码保护
*
* @return string|null
*/
public function password():?string
{
return '123456';
}
}
CSV 方案
对于超大规模数据导出,推荐使用 CSV 格式。虽然异步任务支持大批量数据导出,但 Excel 格式在极大数据量下仍可能出现内存不足问题。CatchAdmin 专业版的 CSV 导出方案经过优化,支持百万级数据导出且内存占用极低。在测试环境中成功导出 130 万条数据,内存消耗控制在合理范围内
php
// CSV 大数据量导出示例
return User::query()
->select('id', 'username', 'email', 'created_at')
->without('roles')
// 必须使用游标查询以确保低内存占用
->cursor()
->downloadAsCsv(['id', '昵称', '邮箱', '创建时间']);
WARNING
记住一定要使用 cursor
游标查询数据,否则会导出失败