国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

springboot項目實現(xiàn)斷點續(xù)傳

這篇具有很好參考價值的文章主要介紹了springboot項目實現(xiàn)斷點續(xù)傳。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

  • java代碼
package com.ruoyi.web.upload.controller;
import com.ruoyi.web.upload.dto.FileChunkDTO;
import com.ruoyi.web.upload.dto.FileChunkResultDTO;
import com.ruoyi.web.upload.result.Result;
import com.ruoyi.web.upload.service.IUploadService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
 * @ProjectName UploaderController
 * @author Administrator
 * @version 1.0.0
 * @Description 附件分片上傳
 * @createTime 2022/4/13 0013 15:58
 */
@RestController
@RequestMapping("upload")
public class UploaderController {
   @Resource
   private IUploadService uploadService;
   /**
    * 檢查分片是否存在
    *
    * @return
    */
   @GetMapping("chunk")
   public Result checkChunkExist(FileChunkDTO chunkDTO) {
      FileChunkResultDTO fileChunkCheckDTO;
      try {
         fileChunkCheckDTO = uploadService.checkChunkExist(chunkDTO);
         return Result.ok(fileChunkCheckDTO);
      } catch (Exception e) {
         return Result.fail(e.getMessage());
      }
   }
   /**
    * 上傳文件分片
    *
    * @param chunkDTO
    * @return
    */
   @PostMapping("chunk")
   public Result uploadChunk(FileChunkDTO chunkDTO) {
      try {
         uploadService.uploadChunk(chunkDTO);
         return Result.ok(chunkDTO.getIdentifier());
      } catch (Exception e) {
         return Result.fail(e.getMessage());
      }
   }
   /**
    * 請求合并文件分片
    *
    * @param chunkDTO
    * @return
    */
   @PostMapping("merge")
   public Result mergeChunks(@RequestBody FileChunkDTO chunkDTO) {
      try {
         boolean success = uploadService.mergeChunk(chunkDTO.getIdentifier(), chunkDTO.getFilename(), chunkDTO.getTotalChunks());
         return Result.ok(success);
      } catch (Exception e) {
         return Result.fail(e.getMessage());
      }
   }
}
package com.ruoyi.web.upload.dto;
import org.springframework.web.multipart.MultipartFile;
/**
 * @ProjectName FileChunkDTO
 * @author Administrator
 * @version 1.0.0
 * @Description 附件分片上傳
 * @createTime 2022/4/13 0013 15:59
 */
public class FileChunkDTO {
   /**
    * 文件 md5
    */
   private String identifier;
   /**
    * 分塊文件
    */
   MultipartFile file;
   /**
    * 當前分塊序號
    */
   private Integer chunkNumber;
   /**
    * 分塊大小
    */
   private Long chunkSize;
   /**
    * 當前分塊大小
    */
   private Long currentChunkSize;
   /**
    * 文件總大小
    */
   private Long totalSize;
   /**
    * 分塊總數(shù)
    */
   private Integer totalChunks;
   /**
    * 文件名
    */
   private String filename;
   public String getIdentifier() {
      return identifier;
   }
   public void setIdentifier(String identifier) {
      this.identifier = identifier;
   }
   public MultipartFile getFile() {
      return file;
   }
   public void setFile(MultipartFile file) {
      this.file = file;
   }
   public Integer getChunkNumber() {
      return chunkNumber;
   }
   public void setChunkNumber(Integer chunkNumber) {
      this.chunkNumber = chunkNumber;
   }
   public Long getChunkSize() {
      return chunkSize;
   }
   public void setChunkSize(Long chunkSize) {
      this.chunkSize = chunkSize;
   }
   public Long getCurrentChunkSize() {
      return currentChunkSize;
   }
   public void setCurrentChunkSize(Long currentChunkSize) {
      this.currentChunkSize = currentChunkSize;
   }
   public Long getTotalSize() {
      return totalSize;
   }
   public void setTotalSize(Long totalSize) {
      this.totalSize = totalSize;
   }
   public Integer getTotalChunks() {
      return totalChunks;
   }
   public void setTotalChunks(Integer totalChunks) {
      this.totalChunks = totalChunks;
   }
   public String getFilename() {
      return filename;
   }
   public void setFilename(String filename) {
      this.filename = filename;
   }
   @Override
   public String toString() {
      return "FileChunkDTO{" +
              "identifier='" + identifier + '\'' +
              ", file=" + file +
              ", chunkNumber=" + chunkNumber +
              ", chunkSize=" + chunkSize +
              ", currentChunkSize=" + currentChunkSize +
              ", totalSize=" + totalSize +
              ", totalChunks=" + totalChunks +
              ", filename='" + filename + '\'' +
              '}';
   }
}
package com.ruoyi.web.upload.dto;
import java.util.Set;
/**
 * @ProjectName FileChunkResultDTO
 * @author Administrator
 * @version 1.0.0
 * @Description 附件分片上傳
 * @createTime 2022/4/13 0013 15:59
 */
public class FileChunkResultDTO {
   /**
    * 是否跳過上傳
    */
   private Boolean skipUpload;
   /**
    * 已上傳分片的集合
    */
   private Set<Integer> uploaded;
   public Boolean getSkipUpload() {
      return skipUpload;
   }
   public void setSkipUpload(Boolean skipUpload) {
      this.skipUpload = skipUpload;
   }
   public Set<Integer> getUploaded() {
      return uploaded;
   }
   public void setUploaded(Set<Integer> uploaded) {
      this.uploaded = uploaded;
   }
   public FileChunkResultDTO(Boolean skipUpload, Set<Integer> uploaded) {
      this.skipUpload = skipUpload;
      this.uploaded = uploaded;
   }
   public FileChunkResultDTO(Boolean skipUpload) {
      this.skipUpload = skipUpload;
   }
}
package com.ruoyi.web.upload.dto;
import lombok.Getter;
/**
   * @Author
   * @Date Created in  2023/2/23 17:25
   * @DESCRIPTION:  統(tǒng)一返回結(jié)果狀態(tài)信息類
   * @Version V1.0
   */
@Getter
@SuppressWarnings("all")
public enum ResultCodeEnum {
    SUCCESS(200,"成功"),
    FAIL(201, "失敗"),
    PARAM_ERROR( 202, "參數(shù)不正確"),
    SERVICE_ERROR(203, "服務異常"),
    DATA_ERROR(204, "數(shù)據(jù)異常"),
    DATA_UPDATE_ERROR(205, "數(shù)據(jù)版本異常"),

    LOGIN_AUTH(208, "未登陸"),
    PERMISSION(209, "沒有權(quán)限"),

    CODE_ERROR(210, "驗證碼錯誤"),
    LOGIN_MOBLE_ERROR(211, "賬號不正確"),
    LOGIN_DISABLED_ERROR(212, "改用戶已被禁用"),
    REGISTER_MOBLE_ERROR(213, "手機號碼格式不正確"),
    REGISTER_MOBLE_ERROR_NULL(214, "手機號碼為空"),

    LOGIN_AURH(214, "需要登錄"),
    LOGIN_ACL(215, "沒有權(quán)限"),

    URL_ENCODE_ERROR( 216, "URL編碼失敗"),
    ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回調(diào)請求"),
    FETCH_ACCESSTOKEN_FAILD( 218, "獲取accessToken失敗"),
    FETCH_USERINFO_ERROR( 219, "獲取用戶信息失敗");
    private Integer code;
    private String message;
    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
package com.ruoyi.web.upload.service;
import com.ruoyi.web.upload.dto.FileChunkDTO;
import com.ruoyi.web.upload.dto.FileChunkResultDTO;
import java.io.IOException;
/**
 * @ProjectName IUploadService
 * @author Administrator
 * @version 1.0.0
 * @Description 附件分片上傳
 * @createTime 2022/4/13 0013 15:59
 */
public interface IUploadService {
   /**
    * 檢查文件是否存在,如果存在則跳過該文件的上傳,如果不存在,返回需要上傳的分片集合
    * @param chunkDTO
    * @return
    */
   FileChunkResultDTO checkChunkExist(FileChunkDTO chunkDTO);
   /**
    * 上傳文件分片
    * @param chunkDTO
    */
   void uploadChunk(FileChunkDTO chunkDTO) throws IOException;
   /**
    * 合并文件分片
    * @param identifier
    * @param fileName
    * @param totalChunks
    * @return
    * @throws IOException
    */
   boolean mergeChunk(String identifier,String fileName,Integer totalChunks)throws IOException;
}
package com.ruoyi.web.upload.service.impl;
import com.ruoyi.web.upload.dto.FileChunkDTO;
import com.ruoyi.web.upload.dto.FileChunkResultDTO;
import com.ruoyi.web.upload.service.IUploadService;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.*;
/**
 * @ProjectName UploadServiceImpl
 * @author Administrator
 * @version 1.0.0
 * @Description 附件分片上傳
 * @createTime 2022/4/13 0013 15:59
 */
@Service
@SuppressWarnings("all")
public class UploadServiceImpl implements IUploadService {
   private Logger logger = LoggerFactory.getLogger(UploadServiceImpl.class);
   @Autowired
   private RedisTemplate redisTemplate;
   @Value("${ruoyi.profile}")
   private String uploadFolder;
   /**
    * 檢查文件是否存在,如果存在則跳過該文件的上傳,如果不存在,返回需要上傳的分片集合
    *  檢查分片是否存在
          ○ 檢查目錄下的文件是否存在。
          ○ 檢查redis存儲的分片是否存在。
          ○ 判斷分片數(shù)量和總分片數(shù)量是否一致。
               如果文件存在并且分片上傳完畢,標識已經(jīng)完成附件的上傳,可以進行秒傳操作。
               如果文件不存在或者分片為上傳完畢,則返回false并返回已經(jīng)上傳的分片信息。
    * @param chunkDTO
    * @return
    */
   @Override
   public FileChunkResultDTO checkChunkExist(FileChunkDTO chunkDTO) {
      //1.檢查文件是否已上傳過
      //1.1)檢查在磁盤中是否存在
      String fileFolderPath = getFileFolderPath(chunkDTO.getIdentifier());
      logger.info("fileFolderPath-->{}", fileFolderPath);
      String filePath = getFilePath(chunkDTO.getIdentifier(), chunkDTO.getFilename());
      File file = new File(filePath);
      boolean exists = file.exists();
      //1.2)檢查Redis中是否存在,并且所有分片已經(jīng)上傳完成。
      Set<Integer> uploaded = (Set<Integer>) redisTemplate.opsForHash().get(chunkDTO.getIdentifier(), "uploaded");
      if (uploaded != null && uploaded.size() == chunkDTO.getTotalChunks() && exists) {
         return new FileChunkResultDTO(true);
      }
      File fileFolder = new File(fileFolderPath);
      if (!fileFolder.exists()) {
         boolean mkdirs = fileFolder.mkdirs();
         logger.info("準備工作,創(chuàng)建文件夾,fileFolderPath:{},mkdirs:{}", fileFolderPath, mkdirs);
      }
      // 斷點續(xù)傳,返回已上傳的分片
      return new FileChunkResultDTO(false, uploaded);
   }
   /**
    * 上傳分片
    *  上傳附件分片
           ○ 判斷目錄是否存在,如果不存在則創(chuàng)建目錄。
           ○ 進行切片的拷貝,將切片拷貝到指定的目錄。
           ○ 將該分片寫入redis
    * @param chunkDTO
    */
   @Override
   public void uploadChunk(FileChunkDTO chunkDTO) {
      //分塊的目錄
      String chunkFileFolderPath = getChunkFileFolderPath(chunkDTO.getIdentifier());
      logger.info("分塊的目錄 -> {}", chunkFileFolderPath);
      File chunkFileFolder = new File(chunkFileFolderPath);
      if (!chunkFileFolder.exists()) {
         boolean mkdirs = chunkFileFolder.mkdirs();
         logger.info("創(chuàng)建分片文件夾:{}", mkdirs);
      }
      //寫入分片
      try (
              InputStream inputStream = chunkDTO.getFile().getInputStream();
              FileOutputStream outputStream = new FileOutputStream(new File(chunkFileFolderPath + chunkDTO.getChunkNumber()))
      ) {
         IOUtils.copy(inputStream, outputStream);
         logger.info("文件標識:{},chunkNumber:{}", chunkDTO.getIdentifier(), chunkDTO.getChunkNumber());
         //將該分片寫入redis
         long size = saveToRedis(chunkDTO);
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
   @Override
   public boolean mergeChunk(String identifier, String fileName, Integer totalChunks) throws IOException {
      return mergeChunks(identifier, fileName, totalChunks);
   }
   /**
    * 合并分片
    *
    * @param identifier
    * @param filename
    */
   private boolean mergeChunks(String identifier, String filename, Integer totalChunks) {
      String chunkFileFolderPath = getChunkFileFolderPath(identifier);
      String filePath = getFilePath(identifier, filename);
      // 檢查分片是否都存在
      if (checkChunks(chunkFileFolderPath, totalChunks)) {
         File chunkFileFolder = new File(chunkFileFolderPath);
         File mergeFile = new File(filePath);
         File[] chunks = chunkFileFolder.listFiles();
         // 切片排序1、2/3、---
         List fileList = Arrays.asList(chunks);
         Collections.sort(fileList, (Comparator<File>) (o1, o2) -> {
            return Integer.parseInt(o1.getName()) - (Integer.parseInt(o2.getName()));
         });
         try {
            RandomAccessFile randomAccessFileWriter = new RandomAccessFile(mergeFile, "rw");
            byte[] bytes = new byte[1024];
            for (File chunk : chunks) {
               RandomAccessFile randomAccessFileReader = new RandomAccessFile(chunk, "r");
               int len;
               while ((len = randomAccessFileReader.read(bytes)) != -1) {
                  randomAccessFileWriter.write(bytes, 0, len);
               }
               randomAccessFileReader.close();
            }
            randomAccessFileWriter.close();
         } catch (Exception e) {
            return false;
         }
         return true;
      }
      return false;
   }
   /**
    * 檢查分片是否都存在
    * @param chunkFileFolderPath
    * @param totalChunks
    * @return
    */
   private boolean checkChunks(String chunkFileFolderPath, Integer totalChunks) {
      try {
         for (int i = 1; i <= totalChunks + 1; i++) {
            File file = new File(chunkFileFolderPath + File.separator + i);
            if (file.exists()) {
               continue;
            } else {
               return false;
            }
         }
      } catch (Exception e) {
         return false;
      }
      return true;
   }
   /**
    * 分片寫入Redis
    * 判斷切片是否已存在,如果未存在,則創(chuàng)建基礎(chǔ)信息,并保存。
    * @param chunkDTO
    */
   private synchronized long saveToRedis(FileChunkDTO chunkDTO) {
      Set<Integer> uploaded = (Set<Integer>) redisTemplate.opsForHash().get(chunkDTO.getIdentifier(), "uploaded");
      if (uploaded == null) {
         uploaded = new HashSet<>(Arrays.asList(chunkDTO.getChunkNumber()));
         HashMap<String, Object> objectObjectHashMap = new HashMap<>();
         objectObjectHashMap.put("uploaded", uploaded);
         objectObjectHashMap.put("totalChunks", chunkDTO.getTotalChunks());
         objectObjectHashMap.put("totalSize", chunkDTO.getTotalSize());
//            objectObjectHashMap.put("path", getFileRelativelyPath(chunkDTO.getIdentifier(), chunkDTO.getFilename()));
         objectObjectHashMap.put("path", chunkDTO.getFilename());
         redisTemplate.opsForHash().putAll(chunkDTO.getIdentifier(), objectObjectHashMap);
      } else {
         uploaded.add(chunkDTO.getChunkNumber());
         redisTemplate.opsForHash().put(chunkDTO.getIdentifier(), "uploaded", uploaded);
      }
      return uploaded.size();
   }
   /**
    * 得到文件的絕對路徑
    *
    * @param identifier
    * @param filename
    * @return
    */
   private String getFilePath(String identifier, String filename) {
      String ext = filename.substring(filename.lastIndexOf("."));
//        return getFileFolderPath(identifier) + identifier + ext;
      return uploadFolder + filename;
   }
   /**
    * 得到文件的相對路徑
    *
    * @param identifier
    * @param filename
    * @return
    */
   private String getFileRelativelyPath(String identifier, String filename) {
      String ext = filename.substring(filename.lastIndexOf("."));
      return "/" + identifier.substring(0, 1) + "/" +
              identifier.substring(1, 2) + "/" +
              identifier + "/" + identifier
              + ext;
   }
   /**
    * 得到分塊文件所屬的目錄
    *
    * @param identifier
    * @return
    */
   private String getChunkFileFolderPath(String identifier) {
      return getFileFolderPath(identifier) + "chunks" + File.separator;
   }
   /**
    * 得到文件所屬的目錄
    *
    * @param identifier
    * @return
    */
   private String getFileFolderPath(String identifier) {
      return uploadFolder + identifier.substring(0, 1) + File.separator +
              identifier.substring(1, 2) + File.separator +
              identifier + File.separator;
//        return uploadFolder;
   }
}
package com.ruoyi.web.upload.result;
import com.ruoyi.web.upload.dto.ResultCodeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @Author
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:  全局統(tǒng)一返回結(jié)果
 * @Version V1.0
 */
@Data
@ApiModel(value = "全局統(tǒng)一返回結(jié)果")
@SuppressWarnings("all")
public class Result<T> {
    @ApiModelProperty(value = "返回碼")
    private Integer code;
    @ApiModelProperty(value = "返回消息")
    private String message;
    @ApiModelProperty(value = "返回數(shù)據(jù)")
    private T data;
    private Long total;
    public Result(){}
    protected static <T> Result<T> build(T data) {
        Result<T> result = new Result<T>();
        if (data != null)
            result.setData(data);
        return result;
    }
    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }
    public static <T> Result<T> build(Integer code, String message) {
        Result<T> result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
    public static<T> Result<T> ok(){
        return Result.ok(null);
    }
    /**
     * 操作成功
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> ok(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }
    public static<T> Result<T> fail(){
        return Result.fail(null);
    }
    /**
     * 操作失敗
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> fail(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }
    public Result<T> message(String msg){
        this.setMessage(msg);
        return this;
    }
    public Result<T> code(Integer code){
        this.setCode(code);
        return this;
    }
    public boolean isOk() {
        if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
            return true;
        }
        return false;
    }
}
  • 前端代碼
  • mainjs導入uploader
import uploader from 'vue-simple-uploader'
Vue.use(uploader)
  • 安裝uploader和spark-md5的依賴
npm install --save vue-simple-uploader
npm install --save spark-md5
  • 創(chuàng)建uploader組件
<template>
  <div>
    <uploader
        :autoStart="false"
        :options="options"
        :file-status-text="statusText"
        class="uploader-example"
        @file-complete="fileComplete"
        @complete="complete"
        @file-success="fileSuccess"
        @files-added="filesAdded"
    >
      <uploader-unsupport></uploader-unsupport>
      <uploader-drop>
        <p>將文件拖放到此處以上傳</p>
        <uploader-btn>選擇文件</uploader-btn>
        <uploader-btn :attrs="attrs">選擇圖片</uploader-btn>
        <uploader-btn :directory="true">選擇文件夾</uploader-btn>
      </uploader-drop>
      <!-- <uploader-list></uploader-list> -->
      <uploader-files> </uploader-files>
    </uploader>
    <br />
    <el-button @click="allStart()" :disabled="disabled">全部開始</el-button>
    <el-button @click="allStop()" style="margin-left: 4px">全部暫停</el-button>
    <el-button @click="allRemove()" style="margin-left: 4px">全部移除</el-button>
  </div>
</template>

<script>
import axios from "axios";
import SparkMD5 from "spark-md5";
import {upload} from "@/api/user";
// import storage from "store";
// import { ACCESS_TOKEN } from '@/store/mutation-types'
export default {
  name: "Home",
  data() {
    return {
      skip: false,
      options: {
        target: "http://localhost:9999/upload/chunk",
        // 開啟服務端分片校驗功能
        testChunks: true,
        parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) {
          return parsedTimeRemaining
              .replace(/\syears?/, "年")
              .replace(/\days?/, "天")
              .replace(/\shours?/, "小時")
              .replace(/\sminutes?/, "分鐘")
              .replace(/\sseconds?/, "秒");
        },
        // 服務器分片校驗函數(shù)
        checkChunkUploadedByResponse: (chunk, message) => {
          const result = JSON.parse(message);
          if (result.data.skipUpload) {
            this.skip = true;
            return true;
          }
          return (result.data.uploaded || []).indexOf(chunk.offset + 1) >= 0;
        },
        // headers: {
        //   // 在header中添加的驗證,請根據(jù)實際業(yè)務來
        //   "Access-Token": storage.get(ACCESS_TOKEN),
        // },
      },
      attrs: {
        accept: "image/*",
      },
      statusText: {
        success: "上傳成功",
        error: "上傳出錯了",
        uploading: "上傳中...",
        paused: "暫停中...",
        waiting: "等待中...",
        cmd5: "計算文件MD5中...",
      },
      fileList: [],
      disabled: true,
    };
  },
  watch: {
    fileList(o, n) {
      this.disabled = false;
    },
  },
  methods: {
    // fileSuccess(rootFile, file, response, chunk) {
    //   // console.log(rootFile);
    //   // console.log(file);
    //   // console.log(message);
    //   // console.log(chunk);
    //   const result = JSON.parse(response);
    //   console.log(result.success, this.skip);
    //
    //   if (result.success && !this.skip) {
    //     axios
    //         .post(
    //             "http://127.0.0.1:9999/upload/merge",
    //             {
    //               identifier: file.uniqueIdentifier,
    //               filename: file.name,
    //               totalChunks: chunk.offset,
    //             },
    //             // {
    //             //   headers: { "Access-Token": storage.get(ACCESS_TOKEN) }
    //             // }
    //         )
    //         .then((res) => {
    //           if (res.data.success) {
    //             console.log("上傳成功");
    //           } else {
    //             console.log(res);
    //           }
    //         })
    //         .catch(function (error) {
    //           console.log(error);
    //         });
    //   } else {
    //     console.log("上傳成功,不需要合并");
    //   }
    //   if (this.skip) {
    //     this.skip = false;
    //   }
    // },
    fileSuccess(rootFile, file, response, chunk) {
      // console.log(rootFile);
      // console.log(file);
      // console.log(message);
      // console.log(chunk);
      const result = JSON.parse(response);
      console.log(result.success, this.skip);
      const user = {
        identifier: file.uniqueIdentifier,
        filename: file.name,
        totalChunks: chunk.offset,
      }
      if (result.success && !this.skip) {
        upload(user).then((res) => {
          if (res.code == 200) {
            console.log("上傳成功");
          } else {
            console.log(res);
          }
        })
            .catch(function (error) {
              console.log(error);
            });
      } else {
        console.log("上傳成功,不需要合并");
      }
      if (this.skip) {
        this.skip = false;
      }
    },
    fileComplete(rootFile) {
      // 一個根文件(文件夾)成功上傳完成。
      // console.log("fileComplete", rootFile);
      // console.log("一個根文件(文件夾)成功上傳完成。");
    },
    complete() {
      // 上傳完畢。
      // console.log("complete");
    },
    filesAdded(file, fileList, event) {
      // console.log(file);
      file.forEach((e) => {
        this.fileList.push(e);
        this.computeMD5(e);
      });
    },
    computeMD5(file) {
      let fileReader = new FileReader();
      let time = new Date().getTime();
      let blobSlice =
          File.prototype.slice ||
          File.prototype.mozSlice ||
          File.prototype.webkitSlice;
      let currentChunk = 0;
      const chunkSize = 1024 * 1024;
      let chunks = Math.ceil(file.size / chunkSize);
      let spark = new SparkMD5.ArrayBuffer();
      // 文件狀態(tài)設(shè)為"計算MD5"
      file.cmd5 = true; //文件狀態(tài)為“計算md5...”
      file.pause();
      loadNext();
      fileReader.onload = (e) => {
        spark.append(e.target.result);
        if (currentChunk < chunks) {
          currentChunk++;
          loadNext();
          // 實時展示MD5的計算進度
          console.log(
              `${currentChunk}分片解析完成, 開始第${
                  currentChunk + 1
              } / ${chunks}分片解析`
          );
        } else {
          let md5 = spark.end();
          console.log(
              `MD5計算完畢:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
                  file.size
              } 用時:${new Date().getTime() - time} ms`
          );
          spark.destroy(); //釋放緩存
          file.uniqueIdentifier = md5; //將文件md5賦值給文件唯一標識
          file.cmd5 = false; //取消計算md5狀態(tài)
          file.resume(); //開始上傳
        }
      };
      fileReader.onerror = function () {
        this.error(`文件${file.name}讀取出錯,請檢查該文件`);
        file.cancel();
      };
      function loadNext() {
        let start = currentChunk * chunkSize;
        let end =
            start + chunkSize >= file.size ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
      }
    },
    allStart() {
      console.log(this.fileList);
      this.fileList.map((e) => {
        if (e.paused) {
          e.resume();
        }
      });
    },
    allStop() {
      console.log(this.fileList);
      this.fileList.map((e) => {
        if (!e.paused) {
          e.pause();
        }
      });
    },
    allRemove() {
      this.fileList.map((e) => {
        e.cancel();
      });
      this.fileList = [];
    },
  },
};
</script>

<style>
.uploader-example {
  width: 100%;
  padding: 15px;
  margin: 0px auto 0;
  font-size: 12px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
.uploader-example .uploader-btn {
  margin-right: 4px;
}
.uploader-example .uploader-list {
  max-height: 440px;
  overflow: auto;
  overflow-x: hidden;
  overflow-y: auto;
}
</style>

文章來源地址http://www.zghlxwxcb.cn/news/detail-682331.html

到了這里,關(guān)于springboot項目實現(xiàn)斷點續(xù)傳的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • spring boot 阿里云oss 文件分片上傳、斷點續(xù)傳

    spring boot 阿里云oss 文件分片上傳、斷點續(xù)傳

    文章目錄 前言 一、申請阿里云oss 二、上代碼 總結(jié) ? ? ? 阿里云對象存儲OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存儲服務,可提供99.9999999999%(12個9)的數(shù)據(jù)持久性,99.995%的數(shù)據(jù)可用性。多種存儲類型供選擇,全面優(yōu)化存儲成本。 ? ? 您可以使用阿

    2024年02月07日
    瀏覽(26)
  • 前端 + 后端 實現(xiàn)分片上傳(斷點續(xù)傳/極速秒傳)

    先記錄下,后面有時間再去實現(xiàn) (已實現(xiàn),可參考 SpringBoot+vue文件上傳下載預覽大文件分片上傳文件上傳進度 SpringBoot+vue 大文件分片下載) 可參考鏈接:vue上傳大文件/視頻前后端(java)代碼 前端slice分片上傳,后端用表記錄分片索引和分片大小和分片總數(shù),當接受完最后

    2023年04月17日
    瀏覽(24)
  • SpringBoot整合minio實現(xiàn)斷點續(xù)傳、分片上傳(附源碼)

    SpringBoot整合minio實現(xiàn)斷點續(xù)傳、分片上傳(附源碼)

    在Web開發(fā)中,大文件的上傳是必不可少的功能之一。本文將介紹如何使用SpringBoot整合minio實現(xiàn)一個簡單的大文件上傳網(wǎng)站。 項目下載 gitee:https://gitee.com/wusupweilgy/springboot-vue.git 前端:vue2、element-ui組件、axios 后端:springboot、minio、mybatis-plus、redis 斷點續(xù)傳 分片上傳 前端顯示

    2024年02月04日
    瀏覽(25)
  • Java實現(xiàn)文件斷點續(xù)傳

    文件斷點續(xù)傳代碼 測試代碼

    2024年03月09日
    瀏覽(27)
  • 【SpringBoot整合系列】SpringBoot 實現(xiàn)大文件分片上傳、斷點續(xù)傳及秒傳

    【SpringBoot整合系列】SpringBoot 實現(xiàn)大文件分片上傳、斷點續(xù)傳及秒傳

    小文件(圖片、文檔、視頻)上傳可以直接使用很多ui框架封裝的上傳組件,或者自己寫一個input 上傳,利用FormData 對象提交文件數(shù)據(jù),后端使用spring提供的MultipartFile進行文件的接收,然后寫入即可。 但是對于比較大的文件,比如上傳2G左右的文件(http上傳),就需要將文件

    2024年04月16日
    瀏覽(37)
  • aliyun-oss-sdk阿里云OSS視頻上傳(斷點續(xù)傳)前端實現(xiàn)

    aliyun-oss-sdk阿里云OSS視頻上傳(斷點續(xù)傳)前端實現(xiàn)

    最近上傳視頻的功能,突然炸了,兩年沒動的代碼,突然不行遼,首次上傳成功,后面繼續(xù)上傳就可以,但凡有一次上傳失敗,再上傳文件就不行。 這里博主使用的是憑證上傳方式哈。 官方文檔:Web(JavaScript)上傳SDK 查看了官方文檔,確實是提到了,如使用1.5.3之前版本重

    2024年02月07日
    瀏覽(25)
  • Vue項目中大文件切片上傳實現(xiàn)秒傳、斷點續(xù)傳的詳細實現(xiàn)教程

    在Vue項目中,大圖片和多數(shù)據(jù)Excel等大文件的上傳是一個非常常見的需求。然而,由于文件大小較大,上傳速度很慢,傳輸中斷等問題也難以避免。因此,為了提高上傳效率和成功率,我們需要使用切片上傳的方式,實現(xiàn)文件秒傳、斷點續(xù)傳、錯誤重試、控制并發(fā)等功能,并

    2024年02月12日
    瀏覽(48)
  • 【前端面試】中大文件上傳/下載:中等文件代理服務器放行+大文件切片傳輸+并發(fā)請求+localstorage實現(xiàn)斷點續(xù)傳

    【前端面試】中大文件上傳/下載:中等文件代理服務器放行+大文件切片傳輸+并發(fā)請求+localstorage實現(xiàn)斷點續(xù)傳

    目錄 切片上傳~spark-md5 原理:流式計算+分塊處理 文件標識spark-md5:A-B A.切片哈希值合并 B.首尾切片+其他切片前中后各取2M 計算hash:A-B(參考React的Fiber架構(gòu)) A.線程:web-worker B.空閑:requestIdleCallback 異步并發(fā)控制:A-B(參考http2的多路復用) A.promise.allSettled() B.并發(fā)數(shù)max=

    2024年02月12日
    瀏覽(30)
  • 【萬字長文】Vue+SpringBoot實現(xiàn)大文件秒傳、斷點續(xù)傳和分片上傳完整教程(提供Gitee源碼)

    前言:最近在實際項目中碰到一個需求,客戶可能會上傳比較大的文件,如果采用傳統(tǒng)的文件上傳方案可能會存在服務器壓力大、資源浪費甚至內(nèi)存溢出的一些安全風險,所以為了解決一系列問題,需要采用新的技術(shù)方案來實現(xiàn)大文件的上傳;空閑的時候參考了網(wǎng)上的一些相

    2024年02月12日
    瀏覽(24)
  • 前端文件上傳(文件上傳,分片上傳,斷點續(xù)傳)

    前端文件上傳(文件上傳,分片上傳,斷點續(xù)傳)

    普通文件上傳 思路: 首先獲取用戶選擇的文件對象,并將其添加到一個 FormData 對象中。然后,使用 axios 的 post 方法將 FormData 對象發(fā)送到服務器。在 then 和 catch 中,我們分別處理上傳成功和失敗的情況,并輸出相應的信息。 需要注意,在使用 axios 進行文件上傳時,必須將

    2024年02月22日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包