Laravel开发excel信息查询系统过程(后台)
2019-09-23 admin laravel 2241
以前的查询项目使用了原生php,通过phpexcel导入表格数据,并提出所有字段给用户选择两个,作为查询条件。
虽然可以实现查询功能,但html,js,php代码混杂,后期修改较为繁琐,手写SQL安全性也无法保证。
因此,准备用全栈框架laravel改写。为提升稳定性和安全性,前后台用户分离,前台使用laravel默认创建的登陆模板,后台使用laravel-admin快速创建。思路如下:
一、导入数据
使用excel3.1导入。先创建后台bgsx数据表和相关controller,用来管理各种查询项目数据。字段为:xmmc项目名称,bm表名,cxtj查询条件,sjsl数据数量,sfkf是否开放,beizhu备注。模型如下:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Encore\Admin\Facades\Admin; class bgsxModel extends Model { protected $table = 'bgsx'; //以字符串的形式存储,定义它的访问器和修改器: public function getcxtjAttribute($value) { return json_decode($value,true);//从数据库读取json字符串,解码成php数组 } public function setcxtjsAttribute($value) { $value = json_encode($value);//编码转换成json字符串存储格式,保存在数据库 $this->attributes['cxtj'] = $value; } }
导入过程,用户填写项目名称(唯一),提交后,使用model读取excel,获取字段创建临时表(如有重复先删除表);然后分批导入到临时表,导入完成后,将临时表重命名为md5(xmmc),防止重复。最后,将项目名称和新表名及查询条件,写入bgsx表。
创建临时表LssjbModel放在App\Model目录下,以导入到lssjb数据表:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Encore\Admin\Facades\Admin; class LssjbModel extends Model { protected $table = 'lssjb'; protected $guarded = [];//禁止批量赋值的字段 public $timestamps = false;//禁用自动创建时间 }
导入excel到临时表,在App\Models目录下建立LssjImport,按 1000 条为基准取出导入的model如下:
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){ if($key == 0){ $table->string($keys[$key])->nullable();//->unique(); 唯一,根据字段酌情使用 }else{ $table->string($keys[$key])->nullable(); } } }); } return new LssjbModel($row);//批量赋值到数据库 } //批量导入1000条 public function batchSize(): int { return 1000; } //以1000条数据基准切割数据 public function chunkSize(): int { return 1000; } }
提交数据时的流程:用户输入项目名称-->选择excel上传-->读取excel-->创建临时数据表-->通过model分批导入数据-->将临时数据表改名为正式表。
保存成功后,默认将所有字段设置为查询条件。如果需要修改,可用右键选择刚才上传的项目,点击编辑,修改查询条件。
相关的controller有:BgsxController.php
namespace App\Admin\Controllers; use App\Models\bgsxModel; use App\Http\Controllers\Controller; use App\Admin\Controllers\CktableController; use Encore\Admin\Controllers\HasResourceActions; use Encore\Admin\Form; use Encore\Admin\Grid; use Encore\Admin\Layout\Content; use Encore\Admin\Show; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; class BgsxController extends Controller { use HasResourceActions; public function index(Content $content) { return $content ->header('查询项目列表') ->description('如需添加新项目请点【上传】') ->body($this->grid()); } public function show($id, Content $content) { return $content ->header('Detail') ->description('description') ->body($this->detail($id)); } public function edit($id, Content $content) { return $content ->header('编辑项目') ->description('description') ->body($this->form($id)->edit($id)); } public function create(Content $content) { return $content ->header('新项目数据') ->description('description') ->body($this->form()); } protected function grid() { $grid = new Grid(new bgsxModel); $grid->id('ID')->sortable(); //$grid->bm('表名'); $grid->xmmc('项目名称'); $grid->cxtj('查询条件'); $grid->sjl('数据量'); $grid->sfkf('是否开放'); $grid->beizhu('查询说明'); $grid->created_at('创建时间')->sortable();//可排序 $grid->updated_at('更新时间')->sortable(); $grid->quickSearch('xmmc');//快捷搜索 $grid->tools(function (Grid\Tools $tools) {$tools->append(new ImportController());});//上传按钮 $grid->actions(function ($actions) {$actions->add(new CktableController);});//添加查看项目数据按钮 $grid->disableCreation();//禁用新增按钮 //筛选功能 $grid->filter(function ($filter) { $filter->disableIdFilter(); // 去掉默认的id过滤器 $filter->like('bm','表名'); // 按字段模糊筛选 $filter->like('xmmc','项目名称'); // 按字段模糊筛选 $filter->between('created_at','创建时间')->datetime(); // 设置created_at字段的范围筛选 $filter->between('updated_at','更新时间')->datetime(); // 设置created_at字段的范围筛选 }); return $grid; } protected function detail($id) { $show = new Show(bgsxModel::findOrFail($id)); $show->id('ID'); $show->bm('表名'); $show->xmmc('项目名称'); $show->cxtj('查询条件')->as(function ($cxtjs) { $cxtj = implode(',',$cxtjs); return $cxtj; }); $show->sjl('数据量'); $show->sfkf('是否开放'); $show->beizhu('查询说明'); $show->created_at('创建时间'); $show->updated_at('更新时间'); return $show; } protected function form() { if (isset(func_get_args()[0])){//获取传递的id $id = func_get_args()[0]; $bm = DB::table('bgsx')->where('id', $id)->value('bm'); $columns = Schema::getColumnListing($bm);//获取所有字段 array_splice($columns,0,1);//去除id $tjsz=array(); foreach($columns as $zdm){ $tjsz[$zdm] = $zdm; } $form = new Form(new bgsxModel); $form->text('bm', '表名')->readonly()->required()->default('lssjb'); $form->text('xmmc', '项目名称')->creationRules(['required', 'min:3', 'max:16', "unique:bgsx"]);//提交表单时检查数据是否已经存在 $form->multipleSelect('cxtj', '查询条件')->options($tjsz); $form->display('创建时间'); $form->display('更新时间'); $form->disableReset(); //关闭撤销键 }else{ $form = new Form(new bgsxModel); $form->text('bm', '表名')->readonly()->required()->default('lssjb'); $form->text('xmmc', '项目名称')->creationRules(['required', 'min:3', 'max:16', "unique:bgsx"]);//提交表单时检查数据是否已经存在 $form->multipleSelect('cxtj', '查询条件'); $form->display('创建时间'); $form->display('更新时间'); $form->disableReset(); //关闭撤销键 } return $form; } }
ImportController.php
namespace App\Admin\Controllers; use App\Models\bgsxModel; use App\Models\LssjbModel; use App\Models\LssjImport; use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\HeadingRowImport; use Illuminate\Support\Facades\Schema;//创建表 use Maatwebsite\Excel\Imports\HeadingRowFormatter; HeadingRowFormatter::default('none');//不格式化标题数据,这两行是关键,少了就无法读取标题导入了。 use Encore\Admin\Controllers\HasResourceActions; use Encore\Admin\Form; use Encore\Admin\Grid; use Encore\Admin\Layout\Content; use Encore\Admin\Show; use Illuminate\Support\Facades\DB; use Encore\Admin\Actions\Action; use Illuminate\Http\Request; class ImportController extends Action { use HasResourceActions; public $name = '新增项目'; protected $selector = '.import-post'; 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 $sjl = LssjbModel::count();//数据量 if ($sjl > 0){ if (Schema::hasTable($zsbm)) {//如果该项目正式数据表已存在,则删除 Schema::drop($zsbm); } Schema::rename($bm, $zsbm); //导入成功,更改临时表为正式表名 //写入bgsx $cxtjs = Schema::getColumnListing($zsbm);//获取所有字段 array_splice($cxtjs,0,1);//去除id $creatbgsx = new bgsxModel; $creatbgsx->bm = $zsbm; $creatbgsx->xmmc = $xmmc; $creatbgsx->sjl = $sjl; $creatbgsx->sfkf = '关闭';//默认关闭查询 $creatbgsx->cxtj = json_encode($cxtjs,true);//默认所有字段作为查询条件,编码转换成json字符串存储格式 $creatbgsx->beizhu = $beizhu; $creatbgsx->save(); return $this->response()->success('导入完成,请设置查询条件!')->refresh(); }else{ return $this->response()->error('数据导入失败,请检查Excel内容是否合规!'); } } public function form() { $this->text('xmmc', '项目名称')->rules('required|min:3|max:16'); $this->text('beizhu', '查询说明')->rules('required|min:3|max:160'); $this->file('file', '选择excel文件')->required()->rules('mimes:xls,xlsx'); }
CktableController.php
namespace App\Admin\Controllers; use Encore\Admin\Actions\RowAction; class CktableController extends RowAction { public $name = '查看数据'; /** * @return string */ public function href() { $key = $this->getKey(); return "/admin/cxbgsj?id=$key"; } }
用于后台编辑各项目具体数据的TableController.php
namespace App\Admin\Controllers; use App\Models\TableModel; use App\Models\TableEditModel; use App\Http\Controllers\Controller; use Encore\Admin\Controllers\HasResourceActions; use Encore\Admin\Form; use Encore\Admin\Grid; use Encore\Admin\Layout\Content; use Encore\Admin\Show; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Encore\Admin\Grid\Displayers\DropdownActions; class TableController extends Controller { use HasResourceActions; /** * Index interface. * * @param Content $content * @return Content */ public function index(Content $content) { if(isset($_GET["id"])){//初次进入,保存表名 $id = $_GET['id']; $bm = DB::table('bgsx')->where('id', $id)->value('bm'); $zwbm = DB::table('bgsx')->where('id', $id)->value('xmmc'); session(['bm' => $bm]);//存储bm到session return $content ->header($zwbm) ->description($bm) ->body($this->grid()); }else{ $bm = session('bm');//后面列表跳转等,读取bm return $content ->header('项目名称:') ->description($bm) ->body($this->grid()); } } /** * Show interface. * * @param mixed $id * @param Content $content * @return Content */ public function show($id,Content $content) { $bm = session('bm');//从session中获取bm return $content ->header('详情') ->description('description') ->body($this->detail($id)); } /** * Edit interface. * * @param mixed $id * @param Content $content * @return Content */ public function edit($id, Content $content) { return $content ->header('修改') ->description('查询条件') ->body($this->form()->edit($id)); } /** * Create interface. * * @param Content $content * @return Content */ public function create(Content $content) { return $content ->header('设置') ->description('查询条件') ->body($this->form()); } protected function grid() { $bm = session('bm');//从session中获取bm $grid = new Grid(new TableModel($bm)); $zdsz = Schema::getColumnListing($bm);//获取所有字段 unset ($zdsz['0']);//去除id,行内编辑加->editable() foreach ($zdsz as $zdm){ $grid->$zdm($zdm)->sortable()->display(function($asset_note) {return str_limit($asset_note, 70, '...');}); } $grid->quickSearch($zdsz);//快捷搜索 $zwbm = DB::table('bgsx')->where('bm', $bm)->value('xmmc');//导出文件名为项目名 $grid->header(function ($query) { //表格头部
以及相应模型TableModel.php
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Encore\Admin\Facades\Admin; class TableModel extends Model { protected $table;//创建属性 public function __construct($bm)//接收控制器变量bm,在函数内部通过func_get_args()函数就可以取得所有传入的参数 { $this->table = $bm;//赋值给table } }
TableEditModel.php
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Encore\Admin\Facades\Admin; class TableEditModel extends Model { protected $table;//创建属性 const UPDATED_AT = null;//去除编辑保存数据时的updated_at字段 const CREATED_AT = null;//去除新建一行数据时的created_at字段 public function __construct()//接收控制器变量bm,在函数内部通过func_get_args()函数就可以取得所有传入的参数 { $this->table = session('bm');//赋值给table } }
后台路由
$router->get('/', 'HomeController@index')->name('admin.home'); $router->resource('/users', UserController::class);//前台用户 $router->resource('/blog', BlogController::class);//博客 $router->resource('/bgsx', BgsxController::class);//excel查询系统 $router->resource('/cxbgsj', TableController::class);//查看表格数据
后台创建完成。