最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot實(shí)現(xiàn)分片上傳、斷點(diǎn)續(xù)傳與進(jìn)度條功能

 更新時(shí)間:2026年02月28日 09:35:46   作者:點(diǎn)我設(shè)置昵稱  
本文介紹了如何使用SpringBoot實(shí)現(xiàn)分片上傳、斷點(diǎn)續(xù)傳和進(jìn)度條等功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

Spring Boot 實(shí)現(xiàn)分片上傳、斷點(diǎn)續(xù)傳與進(jìn)度條

# Spring Boot 實(shí)現(xiàn)分片上傳、斷點(diǎn)續(xù)傳與進(jìn)度條  
## —— 支持 MinIO / RustFS / SeaweedFS 可配置切換
在大文件上傳場景下,傳統(tǒng)單次上傳存在明顯問題:
- 文件過大,失敗后需要整體重傳
- 網(wǎng)絡(luò)不穩(wěn)定,用戶體驗(yàn)差
- 無法展示上傳進(jìn)度
本文基于 **Spring Boot**,實(shí)現(xiàn)一套**生產(chǎn)可用**的大文件上傳方案,支持:
- 分片上傳
- 斷點(diǎn)續(xù)傳
- 上傳進(jìn)度查詢
- MinIO / RustFS / SeaweedFS / 本地存儲
- 通過 yml 配置文件切換存儲類型
---
## 一、整體架構(gòu)設(shè)計(jì)
系統(tǒng)整體采用「接口隔離 + 策略模式」設(shè)計(jì):

Controller ↓ UploadService ↓ StorageService(統(tǒng)一抽象) ↓ MinIO / RustFS / SeaweedFS / Local

**核心思想:上傳邏輯與底層存儲解耦。**
---
## 二、統(tǒng)一配置設(shè)計(jì)
### 1. 存儲類型切換
```yaml
file:
  path: file/
  prefix: pre
  domain: domain/
  storage:
    type: minio   # minio / rustfs / seaweedfs / local

只需修改 storage.type,即可切換存儲實(shí)現(xiàn)。

2. MinIO 配置

minio:
  url: http://localhost:9000
  accessKey: minioadmin
  secretKey: minioadmin123
  bucketName: xxx

3. RustFS 配置(S3 協(xié)議)

rustfs:
  url: http://localhost:9000
  accessKey: rustfsadmin
  secretKey: rustfsadmin
  bucketName: xxx

RustFS 兼容 S3 協(xié)議,可直接復(fù)用 MinIO SDK。

4. SeaweedFS 配置

seaweedfs:
  url: http://127.0.0.1:8333
  accessKey: weed
  secretKey: weed
  bucketName: xxx

三、分片上傳核心流程

1. 前端切片思路

前端將大文件切割為多個(gè)分片(如 5MB):

file
├── chunk_0
├── chunk_1
├── chunk_2
└── chunk_n

每個(gè)分片上傳時(shí)攜帶:

  • 文件唯一標(biāo)識(guid / md5)
  • 分片索引(chunkIndex)
  • 總分片數(shù)(totalChunk)

2. 分片上傳接口

POST /file/chunk/upload

四、斷點(diǎn)續(xù)傳實(shí)現(xiàn)

1. 查詢已上傳分片

GET /file/chunk/uploaded?guid=xxx

返回示例:

[0,1,3,5]

前端只上傳缺失分片即可。

2. 實(shí)現(xiàn)原則

  • 是否已上傳以「存儲層」為準(zhǔn)
  • 不依賴內(nèi)存或 Redis
  • 服務(wù)重啟不影響續(xù)傳

五、上傳進(jìn)度計(jì)算

進(jìn)度 = 已上傳分片數(shù) / 總分片數(shù) × 100%

示例返回:

{
  "uploaded": 6,
  "total": 10,
  "percent": 60
}

六、存儲層抽象設(shè)計(jì)

1. 統(tǒng)一接口定義

public interface StorageService {
    void uploadChunk(String path, InputStream inputStream);
    boolean exists(String path);
    List<Integer> listChunks(String prefix);
    void mergeChunks(String chunkPrefix, String targetPath, int totalChunk);
    void deleteChunks(String chunkPrefix);
}

2. MinIO / RustFS 實(shí)現(xiàn)(S3 通用)

@Slf4j
public class MinioStorageService implements StorageService {
    private final MinioClient minioClient;
    private final String bucket;
    public MinioStorageService(MinioClient client, String bucket) {
        this.minioClient = client;
        this.bucket = bucket;
    }
    @Override
    public void uploadChunk(String path, InputStream inputStream) {
        try {
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(bucket)
                    .object(path)
                    .stream(inputStream, -1, 5 * 1024 * 1024)
                    .build()
            );
        } catch (Exception e) {
            throw new RuntimeException("分片上傳失敗", e);
        }
    }
    @Override
    public boolean exists(String path) {
        try {
            minioClient.statObject(
                StatObjectArgs.builder()
                    .bucket(bucket)
                    .object(path)
                    .build()
            );
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    @Override
    public List<Integer> listChunks(String prefix) {
        List<Integer> chunks = new ArrayList<>();
        Iterable<Result<Item>> results =
            minioClient.listObjects(
                ListObjectsArgs.builder()
                    .bucket(bucket)
                    .prefix(prefix)
                    .build()
            );
        for (Result<Item> r : results) {
            String name = r.get().objectName();
            chunks.add(Integer.parseInt(
                name.substring(name.lastIndexOf("_") + 1)));
        }
        return chunks;
    }
    @Override
    public void mergeChunks(String chunkPrefix,
                            String targetPath,
                            int totalChunk) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            for (int i = 0; i < totalChunk; i++) {
                InputStream in = minioClient.getObject(
                    GetObjectArgs.builder()
                        .bucket(bucket)
                        .object(chunkPrefix + "/chunk_" + i)
                        .build()
                );
                IOUtils.copy(in, out);
            }
            uploadChunk(
                targetPath,
                new ByteArrayInputStream(out.toByteArray()));
        } catch (Exception e) {
            throw new RuntimeException("分片合并失敗", e);
        }
    }
    @Override
    public void deleteChunks(String chunkPrefix) {
        // 可按需實(shí)現(xiàn)批量刪除
    }
}

七、業(yè)務(wù) Service 實(shí)現(xiàn)

@Service
public class FileUploadServiceImpl implements FileUploadService {
    @Autowired
    private StorageService storageService;
    @Override
    public void uploadChunk(ChunkUploadDTO dto) throws IOException {
        String path = dto.getGuid() + "/chunk_" + dto.getChunkIndex();
        if (storageService.exists(path)) {
            return;
        }
        storageService.uploadChunk(
            path, dto.getFile().getInputStream());
    }
    @Override
    public List<Integer> uploadedChunks(String guid) {
        return storageService.listChunks(guid + "/");
    }
    @Override
    public void merge(String guid, int totalChunk) {
        storageService.mergeChunks(
            guid, guid + ".final", totalChunk);
        storageService.deleteChunks(guid + "/");
    }
}

八、Controller 接口

@RestController
@RequestMapping("/file/chunk")
public class FileUploadController {
    @Autowired
    private FileUploadService fileUploadService;
    @PostMapping("/upload")
    public void upload(ChunkUploadDTO dto) throws IOException {
        fileUploadService.uploadChunk(dto);
    }
    @GetMapping("/uploaded")
    public List<Integer> uploaded(@RequestParam String guid) {
        return fileUploadService.uploadedChunks(guid);
    }
    @PostMapping("/merge")
    public void merge(@RequestParam String guid,
                      @RequestParam Integer totalChunk) {
        fileUploadService.merge(guid, totalChunk);
    }
}

九、總結(jié)

本文實(shí)現(xiàn)了一套 Spring Boot 大文件上傳方案,具備:

  • 分片上傳
  • 斷點(diǎn)續(xù)傳
  • 上傳進(jìn)度計(jì)算
  • 多存儲后端解耦
  • yml 配置快速切換

適用于文件中心、數(shù)據(jù)平臺、企業(yè)網(wǎng)盤等場景,可直接用于生產(chǎn)環(huán)境

到此這篇關(guān)于Spring Boot 實(shí)現(xiàn)分片上傳、斷點(diǎn)續(xù)傳與進(jìn)度條的文章就介紹到這了,更多相關(guān)springboot分片上傳斷點(diǎn)續(xù)傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot內(nèi)嵌tomcat處理有特殊字符轉(zhuǎn)義的問題

    SpringBoot內(nèi)嵌tomcat處理有特殊字符轉(zhuǎn)義的問題

    這篇文章主要介紹了SpringBoot內(nèi)嵌tomcat處理有特殊字符轉(zhuǎn)義的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • java 實(shí)現(xiàn)微信服務(wù)器下載圖片到自己服務(wù)器

    java 實(shí)現(xiàn)微信服務(wù)器下載圖片到自己服務(wù)器

    這篇文章主要介紹了 java 實(shí)現(xiàn)微信服務(wù)器下載圖片到自己服務(wù)器的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • SpringBoot部署在Weblogic的操作步驟

    SpringBoot部署在Weblogic的操作步驟

    這篇文章主要介紹了SpringBoot部署在Weblogic的操作步驟,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java使用list集合remove需要注意的事項(xiàng)(使用示例)

    Java使用list集合remove需要注意的事項(xiàng)(使用示例)

    List集合的一個(gè)特點(diǎn)是它其中的元素是有序的,也就是說元素的下標(biāo)是根據(jù)插入的順序來的,在刪除頭部或者中間的一個(gè)元素后,后面的元素下標(biāo)會往前移動,本文給大家介紹Java使用list集合remove需要注意的事項(xiàng),感興趣的朋友一起看看吧
    2022-01-01
  • Java實(shí)現(xiàn)游戲飛機(jī)大戰(zhàn)-III的示例代碼

    Java實(shí)現(xiàn)游戲飛機(jī)大戰(zhàn)-III的示例代碼

    這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)經(jīng)典的游戲之飛機(jī)大戰(zhàn),文中采用了swing技術(shù)進(jìn)行了界面化處理,感興趣的小伙伴可以動手試一試
    2022-02-02
  • SpringBoot?自定義starter?yaml提示失效問題及解決方法

    SpringBoot?自定義starter?yaml提示失效問題及解決方法

    在自定義starter后,必不可少會有properties配置參數(shù)需要指定,而在有時(shí)又不知道為什么出現(xiàn)這個(gè)問題,這篇文章主要介紹了SpringBoot?自定義starter?yaml提示失效問題,需要的朋友可以參考下
    2022-12-12
  • Spring Boot部署到Tomcat過程中遇到的問題匯總

    Spring Boot部署到Tomcat過程中遇到的問題匯總

    這篇文章主要給大家分享了關(guān)于Spring Boot部署到Tomcat過程中遇到的一些問題,文中將解決的方法介紹非常詳細(xì),對同樣遇到這個(gè)問題的朋友具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • SpringBoot項(xiàng)目整合jasypt實(shí)現(xiàn)過程詳解

    SpringBoot項(xiàng)目整合jasypt實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了SpringBoot項(xiàng)目整合jasypt實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • java實(shí)現(xiàn)翻轉(zhuǎn)單詞順序列

    java實(shí)現(xiàn)翻轉(zhuǎn)單詞順序列

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)翻轉(zhuǎn)單詞順序列,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 基于GeoTools和SpringBoot的省域駕車最快路線規(guī)劃方法

    基于GeoTools和SpringBoot的省域駕車最快路線規(guī)劃方法

    本文探討基于GeoTools與SpringBoot的省域駕車最快路線規(guī)劃方法,解決復(fù)雜路況與地理因素影響,通過天地圖API計(jì)算并存儲距離數(shù)據(jù),展示湖南、新疆、黑龍江等地的路線成果,為交通與經(jīng)濟(jì)影響評估提供參考,感興趣的朋友快來一起學(xué)習(xí)吧
    2025-07-07

最新評論

上饶县| 中卫市| 高青县| 黎川县| 砀山县| 安溪县| 麻城市| 陕西省| 铜陵市| 东莞市| 晴隆县| 巍山| 开原市| 上杭县| 古田县| 长沙县| 东方市| 酒泉市| 杂多县| 营山县| 湘潭县| 四平市| 太白县| 华池县| 阆中市| 鹤壁市| 丽水市| 金川县| 班玛县| 密云县| 天柱县| 吉林市| 晴隆县| 清苑县| 且末县| 常州市| 和政县| 许昌县| 南开区| 喀喇| 新竹县|