Laravel 10+ 必须使用 laravel-excel 4.x(对应 PhpSpreadsheet 2.x),3.x 仅支持至 Laravel 8;导入需用 WithChunkReading、withEncoding('UTF-8') 和 WithSkippedEmptyRows 避免内存溢出与乱码;CSV 导出自动遵循 RFC 4180,样式仅对 xlsx 等格式生效;复杂需求需组合事件钩子并确保队列实现。

直接用 maatwebsite/excel 3.x 或 4.x 版本在 Laravel 10+ 里跑 Excel 导入导出,大概率会卡在依赖冲突、PhpSpreadsheet 版本不兼容、或者导出文件打不开——这不是你代码写错了,是插件和 Laravel 主版本之间没对齐。
确认 Laravel 和 laravel-excel 的匹配关系
新版 Laravel(9/10/11)必须用 laravel-excel 4.x;3.x 只支持到 Laravel 8。装错版本会导致 Class "Maatwebsite\Excel\ExcelServiceProvider" not found 或 Call to undefined method Illuminate\Foundation\Application::bindShared() 这类报错。
-
composer require "phpoffice/phpspreadsheet:^2.0"(laravel-excel4.x 强制要求 PhpSpreadsheet 2.x) -
composer require "maatwebsite/excel:^4.0"(别加@dev或^3.1) - Laravel 11 用户注意:
config/excel.php中的'cache' => 'redis'默认不可用,需确保 Redis 配置已启用,否则导入大文件时抛Cache store [redis] is not defined
导入时避免内存溢出和中文乱码
默认 toCollection() 会把整张表读进内存,10 万行 Excel 很容易触发 Allowed memory size exhausted;另外 Windows 系统生成的 Excel 若含中文,常因编码识别失败导致字段值变成 ????。
- 用
toModel()+ chunk 处理:继承WithChunkReading并实现chunkSize()返回 500–1000 - 强制指定输入编码:在
import()调用前加->withEncoding('UTF-8')(仅 4.x 支持) - 跳过空行:实现
WithSkippedEmptyRows,否则空行也会触发model()::create()
导出 CSV 时字段含逗号或换行符怎么办
直接 export(new UsersExport, 'users.csv'),如果用户姓名是 "Zhang, San" 或地址含 "Room 101\nBuilding A",Excel 打开后会错列或换行错乱——CSV 标准要求这些字段必须用双引号包裹,且内部双引号要转义为两个双引号。
- 不用手动拼 CSV 字符串,
laravel-excel4.x 默认已启用 RFC 4180 兼容模式 - 确保导出类中
public function headings(): array返回的每个字段名都用字符串,不要用DB::raw()或动态表达式 - 若仍出错,显式设置 writer 类型:
return (new UsersExport)->download('users.csv', \Maatwebsite\Excel\Excel::CSV);
自定义单元格样式只在 .xlsx 生效,.csv 不支持
很多人试过 WithStyles 接口里的 styles() 方法,发现导出 CSV 时样式完全消失,甚至报错 Call to undefined method PhpOffice\PhpSpreadsheet\Writer\Csv::setStyle()。这不是 bug,是格式限制。
- .csv 是纯文本,没有「字体」「背景色」「边框」概念,所有样式接口只对
xlsx、ods等格式有效 - 导出前判断格式:
if ($this->ext === 'xlsx') { return (new UsersExport)->download('users.xlsx'); } - 若必须带样式导出,禁止用户选 CSV,或前端用 JS 库(如 SheetJS)做客户端导出
class UsersExport implements FromCollection, WithHeadings, WithEvents
{
public function collection()
{
return User::select('name', 'email', 'created_at')->get();
}
public function headings(): array
{
return ['姓名', '邮箱', '注册时间'];
}
public function registerEvents(): array
{
return [
AfterSheet::class => function(AfterSheet $event) {
$event->sheet->getStyle('A1:C1')->applyFromArray([
'font' => ['bold' => true],
'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]],
]);
},
];
}
}
真正麻烦的不是写几行 export 代码,而是当业务要求「导入模板校验、错误行高亮反馈、后台队列异步处理、进度条回传」时,laravel-excel 的事件钩子(OnEachRow、WithValidation、WithProgressBar)得一层层嵌套配置,稍不留神就漏掉 implements ShouldQueue 或忘了在 handle() 里调用 $import->queue()。










