Laravel6.* 安装excel3.1 导入excel文件的两种方法
2019-10-12 admin laravel 1840
创建项目:
composer create-project laravel/laravel weibo
安装excel 3.1
composer require maatwebsite/excel
编辑config/app.php文件,在providers里面添加一行:
'providers' => [ /* * Package Service Providers... */ Maatwebsite\Excel\ExcelServiceProvider::class, ]
在aliases里面添加一行:
'aliases' => [ ... 'Excel' => Maatwebsite\Excel\Facades\Excel::class, ]
生成配置文件(config/excel.php):
php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider"
编辑模型文件app/Imports/UsersImport.php备用,用来导入数据库:
namespace App\Imports; use App\User; use Illuminate\Support\Facades\Hash; use Maatwebsite\Excel\Concerns\ToModel; class UsersImport implements ToModel { /** * @param array $row * * @return User|null */ public function model(array $row) { //dd($row);//写入数据库使用 } }
导入mysql并自动创建表的内容:
namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Imports\UsersImport; use Maatwebsite\Excel\Facades\Excel; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\DB; class UsersController extends Controller { //文件上传方法 public function photo(){ return view('photo'); } //处理文件上传方法 public function upload(Request $request){ //获取上传文件 //var_dump($request->hasFile('excel')); if($request->hasFile('excel')){ //$path = $request->file('excel')->store('excel'); //文件路径,需要开启php的php_fileinfo扩展,store 方法会自动生成唯一的 ID 作为文件名。文件的扩展名将通过检查文件的 MIME 类型来确定。该文件的路径和文件名会被 store 方法返回,以便后续数据库的存储使用。 //echo $path; $originalName = $request->file('excel')->getClientOriginalName(); // 文件原名 $ext = $request->file('excel')->getClientOriginalExtension(); //获取后缀名 $sjkm = str_replace('.'.$ext,"",$originalName);//用于存储数据表名 $sjkm = preg_replace('/\r|\n/', '', $sjkm);//去除换行 $sjkm = str_replace(" ",'',$sjkm);//去除空格 $sjkm = str_replace(".",'',$sjkm);//去除. $sjkm = str_replace("'",'',$sjkm);//去除单引号 if ($ext == 'xls' or $ext == 'xlsx') { $request->file('excel')->move('./Uploads',$originalName); //上传文件移动至指定目录 $path = './Uploads/'.$originalName; echo $path; echo ' 开始读取excel '; $data = Excel::toArray(new UsersImport, $path); $data = $data[0]; //dd($data);//简单的打印一下 $result = $this->create_table($sjkm,$data); if ($result == 1 ){ echo '导入数据成功!'; }else{echo '导入数据库失败! ';} //Excel::import(new UsersImport,$path);//调用模型写入数据库 }else{ echo '文件格式不正确,请上传后缀为xls或xlsx的excel文件! '; back(); } }else{ echo '上传失败!'; back(); } } public function create_table($sjkm,$data)//创建数据表并写入数据 { $tmp = $sjkm; $va = $data; if (Schema::hasTable($tmp)) { echo '数据表已存在,请先删除再上传! '; //Schema::dropIfExists($tmp);//删除数据表 }else{ Schema::create($tmp, function(Blueprint $table) use ($tmp,$va) //create 方法会接收两个参数:一个是数据表的名称,另一个则是接收 $table(Blueprint 实例)的闭包。 { $fields = $va[0]; //列字段 $table->increments('id');//主键 foreach($fields as $key => $value){ if($key == 0){ $table->string($fields[$key])->nullable();//->unique(); 唯一,根据字段酌情使用 }else{ $table->string($fields[$key])->nullable(); } //$fileds_count = $fileds_count + 1; } }); $value_str= array(); $id = 1; foreach($va as $key => $value){ if($key != 0){ foreach($value as $zdnr){//批量替换里面的值 $zdnr = preg_replace('/\r|\n/', '', $zdnr);//去除换行 $zdnr = str_replace(" ",'',$zdnr);//去除空格 $zdnr = str_replace("'",'',$zdnr);//去除单引号 $zdnr = str_replace(",",'',$zdnr);//去除,号 $zdnr = str_replace(",",'',$zdnr);//去除,号 $value_str[] = "'$zdnr'"; } //dd($value_str); $news = implode(",",$value_str); $news = "$id,".$news; DB::insert("insert into $tmp values ($news)"); //$value_str = ''; $value_str= array(); $id = $id + 1; } } return 1; } } }
上面的方法是直接在控制器获取excel数组,再用查询构造器写入,另一个比较好的方法是,用模型分批写入,这样可以用较小的内存,导入数据很大的excel表:
控制器:
public function handle(Request $request) { set_time_limit(60);//导入时长限制1分钟之内完成 ini_set('memory_limit', '100M');//我有内存 我豪啊 $file = $request->file('file');//上传的文件 $bm = 'lssjb';//临时表名 $xmmc = str_replace(' ','',$request->xmmc);//项目名称 $zsbm = md5($xmmc);//生成唯一正式表名 $beizhu = $request->beizhu;//备注的查询说明 if (Schema::hasTable($bm)) {//如果临时数据表已存在,则删除 Schema::drop($bm); } Excel::import(new LssjImport, $file);//用model分批导入到临时数据表lssjb if (Schema::hasTable('lssjb')) {//如果临时数据表创建成功,则可以获取数据量,否则会报错!!! $sjl = LssjbModel::count();//数据量 }else{ //临时数据表创建失败,很可能是excel表格只有一行字段,没有数据,是用来填报的,因此需要用另一种方法导入 $array = Excel::toArray(new UsersImport, $file); $keys = $array[0][0]; //var_dump($keys); Schema::create('lssjb', function(Blueprint $table) use ($keys)//create接收两个参数:表名,$table(Blueprint 实例)的闭包。 { $table->increments('id');//主键 foreach($keys as $key => $value){ $value = str_replace(" ","",$value);//去除空格 if($key == 0){ $table->string($value)->nullable();//->unique(); 唯一,根据字段酌情使用 }else{ $table->string($value)->nullable(); } } }); $sjl = LssjbModel::count();//数据量 } if ($sjl >= 0){ if (Schema::hasTable($zsbm)) {//如果该项目正式数据表已存在,则删除 Schema::drop($zsbm); } Schema::rename($bm, $zsbm);//导入成功,更改临时表为正式表名 //写入bgsx $cxtj = Schema::getColumnListing($zsbm);//获取所有字段 array_splice($cxtj,0,1);//去除id $creatbgsx = new bgsxModel; $creatbgsx->bm = $zsbm; $creatbgsx->xmmc = $xmmc; $creatbgsx->sjl = $sjl; $creatbgsx->sfkf = '关闭';//默认关闭查询 $creatbgsx->cxtj = $cxtj;//默认所有字段作为查询条件 $creatbgsx->beizhu = $beizhu; $creatbgsx->sftb = '关闭';//默认关闭填报 $creatbgsx->tbzd = $cxtj;//默认所有字段开放填报 $creatbgsx->save(); return $this->response()->success('导入完成,请设置查询条件!')->refresh(); }else{ return $this->response()->error('数据导入失败,请检查Excel内容是否合规!'); } }
模型文件:
namespace App\Models; use App\Models\LssjbModel; use Maatwebsite\Excel\Concerns\ToModel; use Maatwebsite\Excel\Concerns\WithBatchInserts; use Maatwebsite\Excel\Concerns\WithChunkReading; use Maatwebsite\Excel\Concerns\WithHeadingRow; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema;//创建表 class LssjImport implements ToModel, WithBatchInserts, WithChunkReading, WithHeadingRow{ public function model(array $row) { if (!Schema::hasTable('lssjb')) {//如果临时数据表不存在,则创建 $keys = array_keys($row); Schema::create('lssjb', function(Blueprint $table) use ($keys)//create接收两个参数:表名,$table(Blueprint 实例)的闭包。 { $table->increments('id');//主键 foreach($keys as $key => $value){ $value = str_replace(" ","",$value);//去除空格 if($key == 0){ $table->string($value)->nullable();//->unique(); 唯一,根据字段酌情使用 }else{ $table->string($value)->nullable(); } } }); } return new LssjbModel($row);//批量赋值到数据库 } //批量导入1000条 public function batchSize(): int { return 1000; } //以1000条数据基准切割数据 public function chunkSize(): int { return 1000; } }
当然,如果需要过滤数据,或者转换数据样式,可以在模型里设置。