laravel-admin 文件上传改为异步分片上传加进度条

ilaravel-admin 是一个很不错的后台管理系统,在此基础上,用好了可以大大减少开发成本,真正做到敏捷开发,但官方文档难免还有一些不足,比如没有如何异步上传、自动上传文件、如何加入进度条、如何解决大文件分片上传等。

官方文档只有一些基础的配置与使用方法laravel-admin官方文档

图片上传

$form->image($column[, $label]);

// 修改图片上传路径和文件名
$form->image($column[, $label])->move($dir, $name);

// 剪裁图片
$form->image($column[, $label])->crop(int $width, int $height, [int $x, int $y]);

// 加水印
$form->image($column[, $label])->insert($watermark, 'center');

// 添加图片删除按钮
$form->image($column[, $label])->removable();

// 删除数据时保留图片
$form->image($column[, $label])->retainable();

// 增加一个下载按钮,可点击下载
$form->image($column[, $label])->downloadable();

文件上传

$form->file($column[, $label]);

// 修改文件上传路径和文件名
$form->file($column[, $label])->move($dir, $name);

// 并设置上传文件类型
$form->file($column[, $label])->rules('mimes:doc,docx,xlsx');

// 添加文件删除按钮
$form->file($column[, $label])->removable();

// 删除数据时保留文件
$form->file($column[, $label])->retainable();

// 增加一个下载按钮,可点击下载
$form->file($column[, $label])->downloadable();
多图/文件上传

其实阅读插件原代码可以发现有一些函数虽然没写在官方文档中,但功能还是在的,如 options 方法,可以直接添加 fileinput 配置,那这样就可以直接设置为异步上传。

$form->file('resource', '上传文件')->options([
                    'maxFileCount'=>1,
                    'maxFileSize'=>1024*500,
                    'allowedFileExtensions'=>['rar','zip','pdf','mp3','mp4','pdf'],
                    'dropZoneEnabled'=>true,
                    'autoReplace'=>true,
                    'browseOnZoneClick'=>true,
                    'showUpload'=>false,
                    'msgSizeTooLarge'=>'文件"{name}" (<b>{size}KB</b>) 超过了允许的最大上传大小<b>{maxSize} KB</b>.',
                    'msgInvalidFileExtension'=>'文件"{name}"的扩展名无效. 仅支持 "{extensions}" 文件.',
                    'dropZoneTitle'=>'将文件拖放到此处',
                    'dropZoneClickTitle'=>'或单击以选择文件',
                    'msgFilesTooMany'=>'选择上载的文件数(2)超过了允许的最大限制1。',
                    'uploadAsync' =>true,
                    'maxFileCount'=>1,
                    'uploadUrl' => 'bookccs/uploadfile',
                    'uploadExtraData' => [
                        '_token'    => csrf_token(),
                        '_method'   => 'POST',
                        'bookid'=>$bookid,
                        'chapterid'=>$chapterid
                    ],
                    'istrue'=>true,
                    
                    
        ])->help('可上传zip,rar格式文件,小于500M');


可以结合bootstrap fileinput插件使用中文说明这篇文章适当更改所需效果,如加入下方方法自动上传文件

Admin::script('
    $("input.resource.action").on("filebatchselected", function(event, files) { 
    if(files.length){
       $(this).fileinput("upload");
     }
    });
');

异步返回信息接收,不管成功失败必须为json格式,如 bookccs/ uploadfile方法,可加入自己所需逻辑。

use Illuminate\Support\Facades\Storage;
public function uploadfile(Request $request){
        $file=$request->file('resource');
        $bookid=\Request::get('bookid');
        $chapterid=\Request::get('chapterid');
        $size =$file->getSize();
         
         if($size > 500*1024*1024){
            $data['code']=404;
            $data['msg']='文件大小不超过500M';
            return json_encode($data);
            exit;
         }
         if($request->hasFile('resource')&&$file->isValid()){
            if($this->saveFiles_1($file)){
                 $filename='guanwang/resourcefile/'.$chapterid;
                 $data['resource_name']= $file->getClientOriginalName();
                 $filenamenew=$filename.'/'.$data['resource_name'];
              
                 $data['resource_size']=round($file->getSize()/1024/1024,2);
                 $data['add_time']=date("Y-m-d H:i:s");
                 $data['chapter_id']=$chapterid;
                 $type=$file->getClientOriginalExtension();
                 
                 if($type=="mp4"){
                     $data['resource_type']=1;
                 }elseif($type=="mp3"){
                     $data['resource_type']=2;
                 }elseif($type=="pdf"){
                     $data['resource_type']=4;
                 }elseif($type=="zip"||$type=="rar"){
                     $data['resource_type']=5;
                 }
                
                if(Storage::disk('oss')->exists($filenamenew)){
                    
                   
                    Storage::disk('oss')->delete($filenamenew);
                 }
                $bool= Storage::disk('oss')->put($filename,$file);
                Storage::disk('oss')->rename($bool, $filenamenew);
                $data['resource_path']=$filenamenew;
             
                $data['resource']=Db::connection('mysql_xxx')->table('xxxx')->insertGetId($data);
                $this->setmoduserid($bookid);
                $data['code']=1;
                return json_encode($data);
            }else{
                $data['code']=404;
                $data['msg']='文件格式不合法'.$file->getMimeType();
                return json_encode($data);
                exit; 
            } 
         }

use Illuminate\Support\Facades\Storage;这是laravel-admin官网指定的将文件上传阿里oss的composer插件,详情可以看laravel 上传文件到阿里云OSS,但此conposer插件并无大文件分片上传的功能。

OSS提供的分片上传(Multipart Upload)功能,将要上传的较大文件(Object)分成多个数据块(Part)来分别上传,上传完成后再调用CompleteMultipartUpload接口将这些Part组合成一个Object来达到断点续传的效果。

如果需要大文件分片上传可以使用阿里云官方文档aliyuncs/oss-sdk-php。

安装

composer require aliyuncs/oss-sdk-php

一些基本操作可以查看php阿里云sdk文档

bookccs/ uploadfile方法改为分片上传

use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Core\OssUtil;
//分片
    public function uploadfile(Request $request){
        $file=$request->file('resource');
        $bookid=\Request::get('bookid');
        $chapterid=\Request::get('chapterid');
        $size =$file->getSize();
        if($size > 500*1024*1024){
            $data['code']=404;
            $data['msg']='文件大小不超过500M';
            return json_encode($data);
            // return $this->response()->error('文件大小不超过500M')->refresh();
            exit;
         }
         if($request->hasFile('resource')&&$file->isValid()){
            if($this->saveFiles_1($file)){
                 $filename='guanwang/resourcefile/'.$chapterid;
                 $data['resource_name']= $file->getClientOriginalName();
                 $filenamenew=$filename.'/'.$data['resource_name'];
                //  if(Storage::disk('oss')->exists($filenamenew)){
                //     $data['code']=404;
                //     $data['msg']='该文件已经存在请删除该文件或者更改文件名后上传'.$file->getClientOriginalName();
                //     return json_encode($data);
                //     exit;
                //  }
                 $data['resource_size']=round($file->getSize()/1024/1024,2);
                 $data['add_time']=date("Y-m-d H:i:s");
                 $data['chapter_id']=$chapterid;
                 $type=$file->getClientOriginalExtension();
                 
                 if($type=="mp4"){
                     $data['resource_type']=1;
                 }elseif($type=="mp3"){
                     $data['resource_type']=2;
                 }elseif($type=="pdf"){
                     $data['resource_type']=4;
                 }elseif($type=="zip"||$type=="rar"){
                     $data['resource_type']=5;
                 }
                
                 
                 
                 
                // $bool= Storage::disk('oss')->put($filename,$file);
                // Storage::disk('oss')->rename($bool, $filenamenew);
                try {
                    $accessKeyId='*****';
                    $accessKeySecret='*****';
                    $endpoint='*****';
                    $bucket='*****';
                    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false);
                    
                    if($ossClient->doesObjectExist($bucket, $filenamenew)){
                        
                        $ids=Db::connection('mysql_zy')->table('tb_resource')->where('resource_path',$filenamenew)->pluck('resource_id');
                        foreach ($ids as $id){
                            if($id){
                                Db::connection('mysql_zy')->table('tb_resource')->where('resource_id',$id)->delete();
                            }
                        }
                        
                        
                         $ossClient->deleteObject($bucket, $filenamenew);
                     }
                    $options = array(
                        OssClient::OSS_CHECK_MD5 => false,
                        OssClient::OSS_PART_SIZE => 10,//10k以上自动分片
                    );

                    $res=$ossClient->multiuploadFile('rdjmobile', $filenamenew, $file, $options);
                }catch (OssException $e) {
                    printf(__FUNCTION__ . ": FAILED\n");
                    printf($e->getMessage() . "\n");
                    return;
                }
                
                
                
                
                
                $data['resource_path']=$filenamenew;
                Db::connection('mysql_zy')->table('tb_book')->where('book_id',$bookid)->update(['last_mod_time'=>date('Y-m-d H:i:s'),'mod_user_id'=>Admin::user()->wid]);
                
                $data['resource']=Db::connection('mysql_zy')->table('tb_resource')->insertGetId($data);
                $this->setmoduserid($bookid);
                $data['code']=1;
                return json_encode($data);
            }else{
                $data['code']=404;
                $data['msg']='文件格式不合法'.$file->getMimeType();
                return json_encode($data);
                
                // return $this->response()->error('文件格式不合法'.$file->getMimeType())->refresh();
                exit; 
            } 
         }
        
    }
    

$ossClient->multiuploadFile阿里封装的快捷分片方法文件大小达到条件时自动分片,也可以根据阿里云文档自己写分片步骤。

接收异步接口返回信息

Admin::script('

  $("input.resource.action").on("fileuploaded", function(event, data, previewId, index) {
                 var res=data.response;
                 console.log(res);
                 
         });
');        

如果返回正确json格式,进度条将自动正确加载,这样一个选择文件后自动异步上传带进度条的上传功能就完成了,如下图

1 评论
内联反馈
查看所有评论

很有用,但除了这篇文章,再就查不到别的更多的资料了
我现在的问题是
编辑时,上传完文件后再点击提交,会发现新的资源路径没有修改到数据库
新增时,上传完文件后会提示”请上传文件”,请问有

最后编辑于 9 月 前 @ dxalone