webuploader大文件分片上传,md5验证附件上传

文章详细描述了一个Vue.js项目中使用WebUploader组件实现大附件上传的过程,包括文件格式检查、分片上传、MD5校验、文件合并及错误处理。特别强调了在分片上传时如何获取每个分片的MD5值,并在上传前进行验证,确保文件完整性。

最近项目需求使用到大附件上传功能,图片最多5M,视频100M,结合查询到的资料决定使用webuploader上传组件,项目展示效果如下:
在这里插入图片描述
流程图:
在这里插入图片描述

1.上传前判断文件格式,项目只支持.png,.jpeg,.jpg,.mp4的视频和图片
2.图片最多5M,视频100M
3.图片可多选上传,视频每次上传一个
4.上传前获取uuid、文件名称和总文件md5判断是否重名和是否已上传过
5.已上传过时跳过上传直接进度显示99,并执行保存缩略图这一步
6.上传时显示上传进度,默认5M分片,大小超出自动分片,获取每个分片的md5
7.上传完成后执行合并操作,将所有分片md5和uuid提交与后端
8.后端验证分片个数和所有分片md5个数,合并后的文件md5和总文件md5,返回保存的附件地址url
9.获取url对应的缩略图并执行保存缩略图

template

<template>
    <el-row class="webUploader">
    <el-col :span="24" class="mb20" :style="{ display: 'flex' }">
      <div class="upload-area" :id="'drag'" v-show="is_upload">
        <div class="upload" ref="selectFile" :id="'up_single'" >
          <div class="upload-icon"><i class="el-icon-upload"></i></div>
          <div class="upload-desc">将文件拖到此处,或<em>点击上传</em></div>
          <div class="upload-tip">支持上传jpg/png/jpeg/mp4格式文件,图片文件不能超过5M,视频文件不能超过100M。</div>
        </div>
      </div>
      <div class="upload-area" v-show="!is_upload">
        <div class="upload" >
          视频素材上传中请稍后......
        </div>
      </div>
      <el-dialog
        title="提示"
        :visible.sync="dialogVisible"
        width="450px"
        :show-close="false"
        :before-close="handleClose">
        <span class="model-title"  slot="title"> 
            <span class="title">上传失败</span>
            <span class="close" @click="dialogVisible = false"><i class="el-icon-close"></i></span>
        </span>
        <div class="model">
            <div class="text">素材不符合上传要求!</div>
            <div class="text">支持上传jpg/png/jpeg/mp4格式文件,图片文件不能超过5M,视频文件不能超过100M。</div>
        </div>
        <span slot="footer" class="dialog-footer">
          <el-button @click="dialogVisible = false" size="small">取 消</el-button>
          <el-button type="primary" @click="dialogVisible = false" size="small">确 定</el-button>
        </span>
      </el-dialog>
      <div class="upload-card" v-if="uploadLoading">
        <div class="title">素材上传进度</div>
        <div class="card-wrap">
          <div class="card-item" v-for="(item,index) in value" :key="index">
            <div class="file-name">
              <i :icon="item.type" class="uploader-file-icon">
                </i>
               <div class="name"> {
   
   {
   
   item.fileName}}</div>
            </div>
            <div class="fileProgress">
              <div class="bar-outer">
                <div class="bar-inner" :style="{width:item.fileProgress+'%'}"></div>
              </div>
              {
   
   {
   
    item.fileProgress+'%' }}
            </div>
          </div>
        </div>
      </div>
    </el-col>

  </el-row>

</template>

script

<script>
//引入webuploader
import WebUploader from "webuploader";
import "webuploader/dist/webuploader.css";
import api from "@/http/api.js";
import BMF from 'browser-md5-file';
var chunkObj = {
   
   };	//用来记录文件的状态、上传中断的位置
var md5Obj = {
   
   };//记录文件分片后所有分片的md5
var GUID = WebUploader.Base.guid();//一个GUID
export default {
   
   
  name: "uploaderList",
  components: {
   
   },
  props: {
   
   
    accept: {
   
   
      type: [String, Object],
      default: null
    },
    // 上传地址
    url: {
   
   
      type: String,
      default: "/mtv_back/api/mtv-backend/sysMaterial/fileUpload",///mtv_back/api/mtv-backend/operate/upLoadFile
    },
    // 上传最大数量 默认为100
    fileNumLimit: {
   
   
      type: Number,
      default: 100
    },
    // 大小限制 默认2M
    fileSingleSizeLimit: {
   
   
      type: Number,
      default: 5120000
    },
    fileType: {
   
   
      type: String,
      default: "knowledge"
    },
    // 上传时传给后端的参数,一般为token,key等
    formData: {
   
   
      type: Object,
      default: () => {
   
   
        return {
   
    uuid: null, code: 9,md5:null };
      }
    },
    // 生成formData中文件的key,下面只是个例子,具体哪种形式和后端商议
    keyGenerator: {
   
   
      type: Function,
      default: () => `${
   
   new Date().getTime()}`
    },
    multiple: {
   
   
      type: Boolean,
      default: true
    },
    // 上传按钮ID
    uploadButton: {
   
   
      type: String,
      default: ""
    },
    value: {
   
   
      type: Array,
      default: () => []
    },
    disabled: {
   
   
      type: Boolean,
      default: () => false
    },
    groupType:{
   
   
      type: String,
      default: ""
    },
  },
  data() {
   
   
    return {
   
   
      uploader: null,
      dialogVisible:false,
      collapse:false,
      panelShow:true,
      uploadLoading:false,
      Filesize:0,
      file_type:'',//保存切换目录之前的type
      is_upload:true,//是否能继续上传,视频每次只能1个,图片可以多个
      fileObj:{
   
   //上传的文件对象

      }
    };
  },
  watch: {
   
   
    disabled(newVal) {
   
   
      if (newVal) {
   
   
        this.uploader.destroy();
        return false;
      }
      this.initWebUpload();
    },
    groupType(newVal){
   
   
      this.groupType = newVal;
    }
  },
  mounted() {
   
   
    if (!this.disabled) {
   
   
      this.$nextTick(()=>{
   
   
        console.log('初始化');
        this.uploader = this.initWebUpload();
      })
    }
  },
  methods: {
   
   
    handleClose(){
   
   
      this.dialogVisible=false;
    },
    initWebUpload() {
   
   
      console.log('初始化2');
      // if (this.uploader) {
   
   
      //   this.uploader.destroy();
      // }
      
      
      let _this = this;
      WebUploader.Uploader.register({
   
   
            "before-send-file":"beforeSendFile",
            "before-send": "beforeSend"
        }, {
   
   
            "beforeSendFile": function (file) {
   
   
                // var deferred = WebUploader.Deferred();
                // this.$axios.post({
   
   
                //     url: "/PublicInfoManage/ResourceFile/isCheckFiles",
                //     data: {
   
   
                //         seq: seq,
                //         fileMd5: $.md5(file.name + file.size + file.ext),
                //         fileName:file.name
                //     },
                //     dataType: "json",
                //     success: function (data) {
   
   
                //         console.log(data);
                //         chunkObj = data;
                //         chunkObj.type = data.type;
                //         chunkObj.chunk == data.chunk;
                //         if (data.type == 0) {
   
   
                            
                //             deferred.reject();
                //             //$("#" + file.id).find(".state").text("文件已上传");
                //         } else if (data.type == 1) {
   
   
                //             if (data.chunk) {
   
   
                //                 deferred.resolve();
                //             }
                //         } else {
   
   
                //             deferred.resolve();
                //         }
                        
                //     },
                //     error: function () {
   
   
                //         deferred.resolve();
                //     }
                // })
                // deferred.resolve();
                // return deferred.promise();
            },
            "beforeSend": function (block) {
   
   //分块对象
              console.log('分块11',block);
                
                let _this = this;
                console.log('分块11',_this); 
                if(_this.options.chunked){
   
   
                  var deferred = WebUploader.Deferred();
                  var curChunk = block.chunk;//第几个分片
                  var totalChunk = block.chunks;//总共几个分片
                  (new WebUploader.Uploader()).md5File(block.file, block.start, block.end)
                  .progress(function(percentage) {
   
   
                    console.log("正在读取文件");
                  })
                  .then(function(val) {
   
   
                    //block.md5 = val;
                    console.log("分块的md5",val);
                    console.log('当前的md5',_this.options.formData.md5);

                    // _this.options.formData.chunk = block.chunk;
                    // _this.options.formData.fileSize =  block.file.size;//分片大小
                    // if(block.file.name.indexOf('.jpg')!=-1 || block.file.name.indexOf('.jpeg')!=-1){
   
   

                    // }else{
   
   
                      
                    // }
                    if(md5Obj[block.file.name]){
   
   
                        md5Obj[block.file.name].md5List[block.chunk] = val;
                      }else{
   
   
                      md5Obj[block.file.name] = {
   
   
                        md5List:[],
                      }
                      md5Obj[block.file.name].md5List[block.chunk] = val;
                    }
                    
                    //deferred.resolve();
                    if(chunkObj[block.file.name] && chunkObj[block.file.name].lackList){
   
   //如果重传只传失败的
                      if(chunkObj[block.file.name].lackList.indexOf(val)!=-1){
   
   
                        //_this.options.formData.md5 = val;
                        _this.options.formData.chunk = block.chunk;
                        _this.options.formData.fileSize =  block.file.size;//分片大小
                        deferred.resolve();
                      }else{
   
   
                        deferred.reject();//跳过此分块
                      }
                    }else{
   
   //
                        //_this.options.formData.md5 = val;
                        _this.options.formData.chunk = block.chunk;
                        _this
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值