文件分片上传

1. 创建一张表,用于接收分片后的文件

 2. 根据表创建一个实体类


import java.io.Serializable;

public class SysFileUpload implements Serializable {
    private Integer fileId;

    private String fileName;

    private String filePath;

    private String fileSuffix;

    private String fileSize;

    private Integer fileShardIndex;

    private String fileShardSize;

    private Integer fileShardTotal;

    private String fileKey;

    private static final long serialVersionUID = 1L;

    public Integer getFileId() {
        return fileId;
    }

    public void setFileId(Integer fileId) {
        this.fileId = fileId;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName == null ? null : fileName.trim();
    }

    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath == null ? null : filePath.trim();
    }

    public String getFileSuffix() {
        return fileSuffix;
    }

    public void setFileSuffix(String fileSuffix) {
        this.fileSuffix = fileSuffix == null ? null : fileSuffix.trim();
    }

    public String getFileSize() {
        return fileSize;
    }

    public void setFileSize(String fileSize) {
        this.fileSize = fileSize == null ? null : fileSize.trim();
    }

    public Integer getFileShardIndex() {
        return fileShardIndex;
    }

    public void setFileShardIndex(Integer fileShardIndex) {
        this.fileShardIndex = fileShardIndex;
    }

    public String getFileShardSize() {
        return fileShardSize;
    }

    public void setFileShardSize(String fileShardSize) {
        this.fileShardSize = fileShardSize == null ? null : fileShardSize.trim();
    }

    public Integer getFileShardTotal() {
        return fileShardTotal;
    }

    public void setFileShardTotal(Integer fileShardTotal) {
        this.fileShardTotal = fileShardTotal;
    }

    public String getFileKey() {
        return fileKey;
    }

    public void setFileKey(String fileKey) {
        this.fileKey = fileKey == null ? null : fileKey.trim();
    }

    /**
     * 扩展属性
     */
    private  String base64;
    public String getBase64() {
        return base64;
    }

    public void setBase64(String base64) {
        this.base64 = base64 == null ? null : base64.trim();
    }

    /**
     * 扩展属性
     */
    private  String fileFlag;
    public String getFileFlag() {
        return fileFlag;
    }

    public void setFileFlag(String fileFlag) {
        this.fileFlag = fileFlag == null ? null : fileFlag.trim();
    }

}

 3. 编写接收分片后的接口

@RequestMapping(value = "/procFile",method = RequestMethod.POST)
    @ResponseBody
    public Map<String,Object>  upload(SysFileUpload fileUpLoad) throws Exception {
        Map<String,Object> map = new HashMap<String, Object>() ;
        String os = System.getProperty("os.name");
        String uploadPath = "";
        if (os.toLowerCase().startsWith("win")) {
            uploadPath = winUploadPath.replace("/", File.separator);
        } else {
            uploadPath = linUploadPath;
        }
        String fileFlag= fileUpLoad.getFileFlag();
        String fileDirPath =uploadPath + File.separator + fileFlag;
        File targetFile = new File(fileDirPath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
         //base64转文件
        MultipartFile multipartFile = Base64ToFileUtil.Base64ToFilepart(fileUpLoad.getBase64());
        //实际存储路径
        String path = fileDirPath+ File.separator +fileUpLoad.getFileKey()+"."+fileUpLoad.getFileShardIndex();
        multipartFile.transferTo(new File(path));

        //文件的相对路径
        fileUpLoad.setFilePath(fileFlag+ File.separator +fileUpLoad.getFileKey());
        //保存文件上传的进度信息
        sysFileUploadService.saveSysFileUpload(fileUpLoad);
        //判断当前分片是否为最后一个
        if(fileUpLoad.getFileShardIndex().equals(fileUpLoad.getFileShardTotal())){
            map.put("code",100);
            map.put("id",fileUpLoad.getFileId());
            map.put("src",fileUpLoad.getFilePath()+"."+fileUpLoad.getFileSuffix());
            fileUpLoad.setFilePath(fileDirPath+File.separator+fileUpLoad.getFileKey());
            //合并分片
            merge(fileUpLoad);
            return map;
        }else{
            map.put("code",200);
            map.put("shardIndex",fileUpLoad.getFileShardIndex());
        }
        return map;
    }

    /**
     * 检查文件上传的进度
     * @param shardKey
     * @return
     */
    @RequestMapping("/checkProgress")
    @ResponseBody
    public Map<String,Object> checkFile(@RequestParam String shardKey){
        Map<String,Object> map = new HashMap<String, Object>();
        SysFileUpload fileUpLoad = sysFileUploadService.selectByKey(shardKey);
        if(fileUpLoad==null){
            //新的文件
            map.put("code",200);
        }else if(fileUpLoad!=null){
            map.put("id",fileUpLoad.getFileId());
            if(fileUpLoad.getFileShardIndex() < fileUpLoad.getFileShardTotal()){
                map.put("code",220);
                map.put("ShardIndex",fileUpLoad.getFileShardIndex()+1);
            }else if(fileUpLoad.getFileShardIndex().equals(fileUpLoad.getFileShardTotal())){
                map.put("code",240);
                map.put("src",fileUpLoad.getFilePath()+"."+fileUpLoad.getFileSuffix());
            }
        }
        return map;
    }


    public void merge(SysFileUpload fileUpLoad) throws Exception {
        Map<String,Object> map = new HashMap<String, Object>();
        //输出文件
        File newfile = new File(fileUpLoad.getFilePath()+"."+fileUpLoad.getFileSuffix());
        //文件追加
        FileOutputStream outputStream =new FileOutputStream(newfile,true);
        //分片文件
        FileInputStream fileInputStream=null;
        byte[] byt=new byte[10*1024*1024];
        int len;
        try {
            for (int i =0;i< fileUpLoad.getFileShardTotal();i++){
                fileInputStream=new FileInputStream(new File(fileUpLoad.getFilePath()+"."+(i+1)));
                while ((len=fileInputStream.read(byt))!=-1){
                    outputStream.write(byt,0,len);
                }
            }
        }catch(IOException e){
            System.out.println("合并异常"+e.toString());
        }finally {
            try{
                if(fileInputStream!=null){
                    fileInputStream.close();
                }
                outputStream.close();
                System.out.println("IO关闭成功");
            }catch (Exception e){
                System.out.println("IO关闭异常"+e);
            }
        }
        System.gc();
        Thread.sleep(100);
        //删除分片
        for (int i=0;i<fileUpLoad.getFileShardTotal();i++){
            String path=fileUpLoad.getFilePath()+"."+(i+1);
            File file = new File(path);
            boolean delete = file.delete();
        }

    }


/**
     * 完成数据包上传
     *
     * @param request
     * @param fileId
     * @return
     */
    @RequestMapping(value = "/finishUpload", method = RequestMethod.GET)
    @ResponseBody
    public Result finishUploadPackage(HttpServletRequest request, @RequestParam("fileId") Integer fileId) {
        Map<String, Object> map = new HashMap<>();
        // 如果有必要请重命名
        map.put("filePath", 文件路径);
        map.put("fileName", 文件名称);
        map.put("code", 100);

        return Result.success(map);
    }

4. 前端上传文件

4.1 计算md5值

import SparkMD5 from 'spark-md5'

/** 计算文件md5值
 * @param file 文件
 * @param chunkSize 分片大小
 * @returns Promise
 */
function getmd5(file, chunkSize) {
    return new Promise((resolve, reject) => {
        let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
        let chunks = Math.ceil(file.size / chunkSize);
        let currentChunk = 0;
        let spark = new SparkMD5.ArrayBuffer();
        let fileReader = new FileReader();
        fileReader.onload = function(e) {
            spark.append(e.target.result);
            currentChunk++;
            if (currentChunk < chunks) {
                loadNext();
            } else {
                let md5 = spark.end();
                resolve(md5);
                //  console.log(md5);
            }
        };
        fileReader.onerror = function(e) {
            reject(e);
        };
        function loadNext() {
            let start = currentChunk * chunkSize;
            let end = start + chunkSize;
            if (end > file.size){
                end = file.size;
            }
            fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
        }
        loadNext();
    });
}

4.2 上传

 // 文件上传之前
    onBeforeUpload(file){
        let text=""
        // 获取文件后缀
        var fileExt =file.name.substring(file.name.lastIndexOf('.')+1).toLowerCase();
        // 文件后缀是否是 zip
        const zipExt = fileExt === 'zip'
        const exeExt = fileExt === 'exe'
        // 文件大小不能超过1G
        const isLimit = file.size / 1024 / 1024 < 1024
        if(!zipExt && !exeExt) {
        text="上传文件只能是 zip或exe 格式!";
        this.$message.error(text)
        return false;
        }
        if (!isLimit) {
        text="上传文件大小不能超过 1GB!";
        this.$message.error(text)
        return false;
        }
        this.fileShardSize = 1*1024 * 1024; //每片文件大小

        //点击后隐藏上传按钮 ,防止重复点击
        //$("#fileUpload").css('visibility','hidden');
        this.showUploadBtn=false
        this.showUploadProcess=true
        this.percentage=1
        var _this=this
        getmd5(file,_this.fileShardSize).then(e =>{
                _this.switchC=false;
                _this.fileShardIndex=1;//分片索引
                _this.curFile=file;
                _this.fileKey=e;
                _this.fileSize=file.size;
                _this.fileShardTotal=Math.ceil(file.size/_this.fileShardSize);//分片总数
                var fileFullName=file.name;
                _this.fileSuffix = fileFullName.substr(fileFullName.lastIndexOf('.') + 1);
                _this.fileName = fileFullName.substr(0, fileFullName.lastIndexOf('.'));

                //上传参数
                var params =  new FormData()
                params.append('fileName', _this.fileName)
                params.append('fileShardTotal', _this.fileShardTotal)
                params.append('fileKey', _this.fileKey)
                params.append('fileSuffix', _this.fileSuffix)
                params.append('fileShardSize', _this.fileShardSize)
                params.append('fileSize', _this.fileSize)
                params.append('fileFlag', _this.flagType)

                _this.updateProgress(file,params)


            })


    },
    // 批量上传
    uploadFile (formData) {
      var _this=this
      // 上传  上边的 procFile 接口
      procFile(formData).then(res => {
        if(res.data.code==200){
          //上传分片完成
          if(res.data.shardIndex<_this.fileShardTotal){
            _this.fileShardIndex=_this.fileShardIndex+1;
            _this.start=(_this.fileShardIndex-1)*_this.fileShardSize;
            _this.end =Math.min(_this.curFile.size,_this.start+_this.fileShardSize);
            _this.fileSize=_this.curFile.size;
            var params =  new FormData()
            params.append('fileName', _this.fileName)
            params.append('fileShardTotal', _this.fileShardTotal)
            params.append('fileKey', _this.fileKey)
            params.append('fileSuffix', _this.fileSuffix)
            params.append('fileShardSize', _this.fileShardSize)
            params.append('fileSize', _this.fileSize)
            params.append('fileFlag', _this.flagType)
            params.append('fileShardIndex', _this.fileShardIndex)
            var fileShardtem=_this.curFile.slice(_this.start,_this.end);//从文件中获取当前分片数据
            let fileReader = new FileReader();
            //异步读取本地文件分片数据并转化为base64字符串
            fileReader.readAsDataURL(fileShardtem);
            //本地异步读取成功后,进行上传
            fileReader.onload = function (e) {
              let  base64str = e.target.result;
              params.append('base64', base64str)
              _this.uploadFile(params)
            }
            let perentNum=Math.ceil(this.fileShardIndex * 100 / this.fileShardTotal)
            if(perentNum>100){
              this.percentage=100
            }else{
              this.percentage=perentNum
            }
          }
        }else if(res.data.code==100){
          var fileId= res.data.id
          //上传完成
          _this.percentage=100
          _this.switchC=true

          _this.finishUpload(fileId)
        }
        console.log(this.percentage)
      }).catch((error)=>{
        if(error.response){
        console.log(error.response.data)
        console.log(error.response.status)
        console.log(error.response.headers)
        }else{
          console.log(error.message)
        }
      })

    },
    updateProgress(file,params){
      var _this= this
      var param = new URLSearchParams()
      param.append('shardKey', _this.fileKey)
      // 批量上传  请求上边的checkProgress接口
      checkProgress(param).then(res => {
        if(res.data.code==200){
          //新文件
          _this.start=(_this.fileShardIndex-1)*_this.fileShardSize;
          _this.end =Math.min(file.size,_this.start+_this.fileShardSize);
          _this.fileShard=file.slice(_this.start,_this.end);//从文件中获取当前分片数据
        }else if(res.data.code==220){
          _this.fileShardIndex=res.data.ShardIndex;
          //有上传未完成的
          _this.start=(_this.fileShardIndex-1)*_this.fileShardSize;
          _this.end =Math.min(file.size,_this.start+_this.fileShardSize);
          _this.fileShard=file.slice(_this.start,_this.end);//从文件中获取当前分片数据
        }else if (res.data.code==240){
          //急速上传
          var fileId= res.data.id
          _this.percentage=100
          _this.switchC=true
          console.log(this.percentage)
          // this.$message({
          //   message: '极速上传成功',
          //   type: 'success'
          // })
          _this.finishUpload(fileId)
          return false;
        }
        //读取base64str
        let fileReader = new FileReader();
        //异步读取本地文件分片并转化为base64字符串
        fileReader.readAsDataURL(_this.fileShard);
        //本地异步读取成功,进行上传
        fileReader.onload=function (e){
          let  base64str=e.target.result;
          params.append('base64', base64str)
          params.append('fileShardIndex', _this.fileShardIndex)
          if(_this.switchC==false){
              _this.uploadFile(params)
          }
        }
      }).catch((error)=>{
        this.$message.error('上传错误')
      })

    },
    finishUpload(fileId){
         var _this=this
           //进行保存提醒
          _this.uploadMsg = _this.$message({
                              duration:0,
                              message: "请稍等,正在保存...",
                              type: "warning"
                            });
        // 上边文件上传成功后的接口
          finishUploadPackage(fileId).then(res => {
            if(res.data.code==100){
                let uploadFileName= res.data.data.fileName
                let uploadFilePath= res.data.data.filePath
               
                _this.fileList = []
                if(uploadFileName != null && uploadFileName.length > 0){
                  var fileObj = { name: uploadFileName , filePath:uploadFilePath}
                  _this.fileList.push(fileObj)
                }
                //关闭消息提醒
                _this.uploadMsg.close()
                
                //上传完成提示
                _this.$message({
                  duration:2000,
                  message: '上传已完成',
                  type: 'success'
                })
              _this.showUploadProcess=false
              _this.showUploadBtn=true
            }
          })

    },

5. 文件上传,参考:组件 | Element

<el-upload
                  class="upload-demo inline-block margin-left-10 margin-right-10"
                  ref="elUpload"
                  action="#"
                  :show-file-list="false"
                  multiple
                  :limit="1"
                  :before-upload="onBeforeUpload"
                >
                  <!-- before-upload:上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。 -->
                  <el-button size="min" icon="el-icon-upload" type="primary" style="" v-show="showUploadBtn">批量上传</el-button>
                  <el-progress style="width:350px;margin-top:50px;margin-left:10px"  v-show="showUploadProcess" color="green" type="line"  :text-inside="true" :stroke-width="20" :percentage="percentage"></el-progress>
                </el-upload>
                 <el-upload
                  ref="elUploadResult"
                  action="#"
                  :show-file-list="true"
                  :file-list="fileList"
                  :limit="1"
                  :before-remove="handleBeforeRemove"
                  :on-remove="handleRemove"
                >
               </el-upload>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值