欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot項(xiàng)目實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能

 更新時(shí)間:2023年08月30日 14:16:27   作者:婲落ヽ紅顏誶  
這篇文章主要介紹了springboot項(xiàng)目實(shí)現(xiàn)斷點(diǎn)續(xù)傳,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

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());
      }
   }
   /**
    * 請(qǐng)求合并文件分片
    *
    * @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;
   /**
    * 當(dāng)前分塊序號(hào)
    */
   private Integer chunkNumber;
   /**
    * 分塊大小
    */
   private Long chunkSize;
   /**
    * 當(dāng)前分塊大小
    */
   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, "服務(wù)異常"),
    DATA_ERROR(204, "數(shù)據(jù)異常"),
    DATA_UPDATE_ERROR(205, "數(shù)據(jù)版本異常"),
    LOGIN_AUTH(208, "未登陸"),
    PERMISSION(209, "沒有權(quán)限"),
    CODE_ERROR(210, "驗(yàn)證碼錯(cuò)誤"),
    LOGIN_MOBLE_ERROR(211, "賬號(hào)不正確"),
    LOGIN_DISABLED_ERROR(212, "改用戶已被禁用"),
    REGISTER_MOBLE_ERROR(213, "手機(jī)號(hào)碼格式不正確"),
    REGISTER_MOBLE_ERROR_NULL(214, "手機(jī)號(hào)碼為空"),
    LOGIN_AURH(214, "需要登錄"),
    LOGIN_ACL(215, "沒有權(quán)限"),
    URL_ENCODE_ERROR( 216, "URL編碼失敗"),
    ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回調(diào)請(qǐng)求"),
    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存儲(chǔ)的分片是否存在。
          ○ 判斷分片數(shù)量和總分片數(shù)量是否一致。
               如果文件存在并且分片上傳完畢,標(biāo)識(shí)已經(jīng)完成附件的上傳,可以進(jìn)行秒傳操作。
               如果文件不存在或者分片為上傳完畢,則返回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("準(zhǔn)備工作,創(chuàng)建文件夾,fileFolderPath:{},mkdirs:{}", fileFolderPath, mkdirs);
      }
      // 斷點(diǎn)續(xù)傳,返回已上傳的分片
      return new FileChunkResultDTO(false, uploaded);
   }
   /**
    * 上傳分片
    *  上傳附件分片
           ○ 判斷目錄是否存在,如果不存在則創(chuàng)建目錄。
           ○ 進(jìn)行切片的拷貝,將切片拷貝到指定的目錄。
           ○ 將該分片寫入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("文件標(biāo)識(shí):{},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();
   }
   /**
    * 得到文件的絕對(duì)路徑
    *
    * @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;
   }
   /**
    * 得到文件的相對(duì)路徑
    *
    * @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 = "返回?cái)?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導(dǎo)入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",
        // 開啟服務(wù)端分片校驗(yàn)功能
        testChunks: true,
        parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) {
          return parsedTimeRemaining
              .replace(/\syears?/, "年")
              .replace(/\days?/, "天")
              .replace(/\shours?/, "小時(shí)")
              .replace(/\sminutes?/, "分鐘")
              .replace(/\sseconds?/, "秒");
        },
        // 服務(wù)器分片校驗(yàn)函數(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中添加的驗(yàn)證,請(qǐng)根據(jù)實(shí)際業(yè)務(wù)來
        //   "Access-Token": storage.get(ACCESS_TOKEN),
        // },
      },
      attrs: {
        accept: "image/*",
      },
      statusText: {
        success: "上傳成功",
        error: "上傳出錯(cuò)了",
        uploading: "上傳中...",
        paused: "暫停中...",
        waiting: "等待中...",
        cmd5: "計(jì)算文件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) {
      // 一個(gè)根文件(文件夾)成功上傳完成。
      // console.log("fileComplete", rootFile);
      // console.log("一個(gè)根文件(文件夾)成功上傳完成。");
    },
    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è)為"計(jì)算MD5"
      file.cmd5 = true; //文件狀態(tài)為“計(jì)算md5...”
      file.pause();
      loadNext();
      fileReader.onload = (e) => {
        spark.append(e.target.result);
        if (currentChunk < chunks) {
          currentChunk++;
          loadNext();
          // 實(shí)時(shí)展示MD5的計(jì)算進(jìn)度
          console.log(
              `第${currentChunk}分片解析完成, 開始第${
                  currentChunk + 1
              } / ${chunks}分片解析`
          );
        } else {
          let md5 = spark.end();
          console.log(
              `MD5計(jì)算完畢:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
                  file.size
              } 用時(shí):${new Date().getTime() - time} ms`
          );
          spark.destroy(); //釋放緩存
          file.uniqueIdentifier = md5; //將文件md5賦值給文件唯一標(biāo)識(shí)
          file.cmd5 = false; //取消計(jì)算md5狀態(tài)
          file.resume(); //開始上傳
        }
      };
      fileReader.onerror = function () {
        this.error(`文件${file.name}讀取出錯(cuò),請(qǐng)檢查該文件`);
        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>

到此這篇關(guān)于springboot項(xiàng)目實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能的文章就介紹到這了,更多相關(guān)springboot斷點(diǎn)續(xù)傳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java應(yīng)用層協(xié)議WebSocket實(shí)現(xiàn)消息推送

    Java應(yīng)用層協(xié)議WebSocket實(shí)現(xiàn)消息推送

    后端向前端推送消息就需要長(zhǎng)連接,首先想到的就是websocket,下面這篇文章主要給大家介紹了關(guān)于java后端+前端使用WebSocket實(shí)現(xiàn)消息推送的詳細(xì)流程,需要的朋友可以參考下
    2023-02-02
  • Java實(shí)現(xiàn)聊天室界面

    Java實(shí)現(xiàn)聊天室界面

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)聊天室界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • SpringBoot中配置雙數(shù)據(jù)源的實(shí)現(xiàn)示例

    SpringBoot中配置雙數(shù)據(jù)源的實(shí)現(xiàn)示例

    在許多應(yīng)用程序中,可能會(huì)遇到需要連接多個(gè)數(shù)據(jù)庫(kù)的情況,本文主要介紹了SpringBoot中配置雙數(shù)據(jù)源的實(shí)現(xiàn)示例,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • Nacos框架與原理之Nacos的參數(shù)

    Nacos框架與原理之Nacos的參數(shù)

    這篇文章主要介紹了Nacos框架與原理之Nacos的參數(shù),Nacos?中的參數(shù)有很多,如:命名空間、分組名、服務(wù)名、保護(hù)閾值、服務(wù)路由類型、臨時(shí)實(shí)例等,但下面文章我們要講解的是參數(shù),參數(shù)是什么呢,下面一起進(jìn)去文章學(xué)習(xí)詳細(xì)內(nèi)容吧
    2022-05-05
  • mybatis-plus報(bào)錯(cuò)Not Found TableInfoCache異常問題

    mybatis-plus報(bào)錯(cuò)Not Found TableInfoCache異常問題

    在集成百度uid-generator過程中,MyBatis-Plus報(bào)錯(cuò)NotFoundTableInfoCache異常,解決方法:檢查實(shí)體類是否繼承了官方model,確保實(shí)體類對(duì)應(yīng)的mapper已正確注入,在使用@Component注解時(shí),應(yīng)保證相關(guān)依賴已注入
    2024-09-09
  • SpringBoot中過濾器Filter+JWT令牌實(shí)現(xiàn)登錄驗(yàn)證

    SpringBoot中過濾器Filter+JWT令牌實(shí)現(xiàn)登錄驗(yàn)證

    本文主要介紹了SpringBoot中過濾器Filter+JWT令牌實(shí)現(xiàn)登錄驗(yàn)證,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • Java遞歸方法求5!的實(shí)現(xiàn)代碼

    Java遞歸方法求5!的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java遞歸方法求5!的實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2017-02-02
  • ArrayList源碼和多線程安全問題分析

    ArrayList源碼和多線程安全問題分析

    這篇文章主要介紹了ArrayList源碼和多線程安全問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面小編和大家一起來學(xué)習(xí)一下吧
    2019-05-05
  • javaweb啟動(dòng)時(shí)啟動(dòng)socket服務(wù)端代碼實(shí)現(xiàn)

    javaweb啟動(dòng)時(shí)啟動(dòng)socket服務(wù)端代碼實(shí)現(xiàn)

    這篇文章主要介紹了javaweb啟動(dòng)時(shí)啟動(dòng)socket服務(wù)端代碼實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java求素?cái)?shù)和最大公約數(shù)的簡(jiǎn)單代碼示例

    Java求素?cái)?shù)和最大公約數(shù)的簡(jiǎn)單代碼示例

    這篇文章主要介紹了Java求素?cái)?shù)和最大公約數(shù)的簡(jiǎn)單代碼示例,其中作者創(chuàng)建的Fraction類可以用來進(jìn)行各種分?jǐn)?shù)運(yùn)算,需要的朋友可以參考下
    2015-09-09

最新評(píng)論