laravel-admin框架下自带的导出功能下不动数据,总是下载失败或者处理超时报500
后台需要一次性导出一份万行数据,由于种种原因laravel自带的导出功能无法满足要求。但是想来想去寻思着几万行的数据怎么就搞不定了呢,太离谱了。最后尝试了使用header头直接下载以及三方插件的方式重写两种方式,都可以解决问题。
导致这样问题的原因一般都是因为在grid()方法中使用了太多次数据库查询或者嵌套查询了,导致执行下载的时候做了很多次mysql操作。除此以外laravel-admin自带的下载本身就是比较吃内存的。
方案一:这里先贴出来header头的方式下载
class TopicStrongExporter extends AbstractExporter implements FromCollection
{
use Exportable;
protected $topic_id;
protected $topic_title;
public function __construct($topic_title, $topic_id)
{
$this->topic_title = $topic_title;
$this->topic_id = $topic_id;
}
public function collection()
{
//重写collection方法
//流写入
$query = Employee::select('employees.*', 'meedu_topics_reads.topic_id', 'meedu_topics_reads.created_at')
->leftJoin('users', 'users.employee_id', '=', 'employees.id')
->Join('meedu_topics_reads', function ($join) {
$join->on('users.id', '=', 'meedu_topics_reads.user_id')
->where('meedu_topics_reads.topic_id', $this->top_id);
}, null, null, 'left')
set_time_limit(0);
$columns = [
'工号',
'姓名',
'是否阅读',
'完成时间',
];
$fileName = '管理明细.csv';
//设置好告诉浏览器要下载excel文件的headers
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
$fp = fopen('php://output', 'a');//打开output流
mb_convert_variables('GBK', 'UTF-8', $columns);
fputcsv($fp, $columns); //将数据格式化为CSV格式并写入到output流中
//也可以设置一个perSize做成一个分页下载
foreach ($query as $item) {
$rowData = [
$item['number'],
$item['name'],
$item['topic_id'] ? "是" : "否",
$item['created_at'],
];
mb_convert_variables('GBK', 'UTF-8', $rowData);
fputcsv($fp, $rowData);
unset($rowData);
}
unset($accessLog);//释放变量的内存
ob_flush(); //刷新输出缓冲到浏览器
flush(); //必须同时使用 ob_flush() 和flush() 函数来刷新输出缓冲。
fclose($fp);
exit();
}
}
这样写可以实现秒下,但是我觉得有点难受,而且后期如果下载的表格样式又要求的话又要大改了,所以我又向前一步用了三方插件。很多人推荐了fast-excel,嗯确实不错就是和laravel-admin相结合的经验贴不多,还是老老实实用了laravel-excel插件
方案二:使用laravel-excel插件
//主要还是继承了AbstractExporter ,实现了几个接口重写了collection方法
class TopicStrongExporter extends AbstractExporter implements FromCollection, WithMapping, WithHeadings
{
use Exportable;
protected $topic_id;
protected $topic_title;
public function __construct($topic_title, $topic_id)
{
$this->topic_title = $topic_title;
$this->topic_id = $topic_id;
}
protected $fileName = "阅读统计.xlsx";
public function headings(): array
{
return [
'工号',
'姓名',
'是否阅读',
'完成时间',
];
}
public function map($row): array
{
return [
$row->number,
$row->name,
$row->topic_id ? "是" : "否",
$row->created_at,
];
}
public function collection()
{
$query = Employee::select('employees.*', 'meedu_topics_reads.topic_id')
->LeftJoin('users', 'users.employee_id', '=', 'employees.id')
->Join('meedu_topics_reads', function ($join) {
$join->on('users.id', '=', 'meedu_topics_reads.user_id')
->where('meedu_topics_reads.topic_id', $this->topic_id);
}, null, null, 'left')
return $query->cursor();
}
public function export()
{
$this->download($this->fileName)->prepare(request())->send();
exit;
}
}
(以上纯属采坑总结,侵删)