laravel-admin下使用header头下载

项目场景:

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;
    }
}

(以上纯属采坑总结,侵删)

你可能感兴趣的:(爬坑总结,laravel)