国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

SpringBoot大文件上傳卡死?分塊切割術搞定GB級傳輸,速度飆升!

開發 前端
Spring Boot實現文件分塊上傳解決了大文件傳輸的核心痛點,結合斷點續傳、分塊驗證和安全控制,可構建出健壯的企業級文件傳輸方案。本文提供的代碼可直接集成到生產環境,根據實際需求調整分塊大小和并發策略。

在互聯網應用中,大文件上傳是一個常見而棘手的挑戰。傳統的單文件上傳方式在面對大文件時經常面臨超時、內存溢出等問題。本文將深入探討如何利用Spring Boot實現高效的分塊上傳方案,解決大文件傳輸痛點。

一、為什么需要文件分塊上傳?

當文件上傳超過100MB時,傳統上傳方式存在三大痛點:

  • 網絡傳輸不穩定: 單次請求時間長,容易中斷
  • 服務器資源耗盡: 大文件一次性加載導致內存溢出
  • 上傳失敗代價高: 需要重新上傳整個文件

分塊上傳的優勢

  • 減小單次請求負載
  • 支持斷點續傳
  • 并發上傳提高效率
  • 降低服務器內存壓力

二、分塊上傳核心原理

圖片圖片

三、Spring Boot實現方案

1. 核心依賴
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.11.0</version>
    </dependency>
</dependencies>
2. 關鍵控制器實現
@RestController
@RequestMapping("/upload")
publicclassChunkUploadController{
    
    privatefinal String CHUNK_DIR = "uploads/chunks/";
    privatefinal String FINAL_DIR = "uploads/final/";
    
    /**
     * 初始化上傳
     * @param fileName 文件名
     * @param fileMd5 文件唯一標識
     */
    @PostMapping("/init")
    public ResponseEntity<String> initUpload(
            @RequestParam String fileName,
            @RequestParam String fileMd5){
        
        // 創建分塊臨時目錄
        String uploadId = UUID.randomUUID().toString();
        Path chunkDir = Paths.get(CHUNK_DIR, fileMd5 + "_" + uploadId);
        try {
            Files.createDirectories(chunkDir);
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("創建目錄失敗");
        }
        return ResponseEntity.ok(uploadId);
    }
    
    /**
     * 上傳分塊
     * @param chunk 分塊文件
     * @param index 分塊索引
     */
    @PostMapping("/chunk")
    public ResponseEntity<String> uploadChunk(
            @RequestParam MultipartFile chunk,
            @RequestParam String uploadId,
            @RequestParam String fileMd5,
            @RequestParam Integer index){
        
        // 生成分塊文件名
        String chunkName = "chunk_" + index + ".tmp";
        Path filePath = Paths.get(CHUNK_DIR, fileMd5 + "_" + uploadId, chunkName);
        
        try {
            chunk.transferTo(filePath);
            return ResponseEntity.ok("分塊上傳成功");
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("分塊保存失敗");
        }
    }
    
    /**
     * 合并文件分塊
     */
    @PostMapping("/merge")
    public ResponseEntity<String> mergeChunks(
            @RequestParam String fileName,
            @RequestParam String uploadId,
            @RequestParam String fileMd5){
        
        // 1. 獲取分塊目錄
        File chunkDir = new File(CHUNK_DIR + fileMd5 + "_" + uploadId);
        
        // 2. 獲取排序后的分塊文件
        File[] chunks = chunkDir.listFiles();
        if (chunks == null || chunks.length == 0) {
            return ResponseEntity.badRequest().body("無分塊文件");
        }
        
        Arrays.sort(chunks, Comparator.comparingInt(f -> 
            Integer.parseInt(f.getName().split("_")[1].split("\\.")[0])));
        
        // 3. 合并文件
        Path finalPath = Paths.get(FINAL_DIR, fileName);
        try (BufferedOutputStream outputStream = 
             new BufferedOutputStream(Files.newOutputStream(finalPath))) {
            
            for (File chunkFile : chunks) {
                Files.copy(chunkFile.toPath(), outputStream);
            }
            
            // 4. 清理臨時分塊
            FileUtils.deleteDirectory(chunkDir);
            
            return ResponseEntity.ok("文件合并成功:" + finalPath);
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("合并失敗:" + e.getMessage());
        }
    }
}
3. 高性能文件合并優化

當處理超大文件(10GB以上)時,需要避免將所有內容加載到內存:

// 使用RandomAccessFile提高性能
publicvoidmergeFiles(File targetFile, List<File> chunkFiles)throws IOException {
    
    try (RandomAccessFile target = 
         new RandomAccessFile(targetFile, "rw")) {
        
        byte[] buffer = newbyte[1024 * 8]; // 8KB緩沖區
        long position = 0;
        
        for (File chunk : chunkFiles) {
            try (RandomAccessFile src = 
                 new RandomAccessFile(chunk, "r")) {
                
                int bytesRead;
                while ((bytesRead = src.read(buffer)) != -1) {
                    target.write(buffer, 0, bytesRead);
                }
                position += chunk.length();
            }
        }
    }
}

四、前端實現關鍵代碼(Vue示例)

1. 分塊處理函數
// 5MB分塊大小
const CHUNK_SIZE = 5 * 1024 * 1024; 

/**
 * 處理文件分塊
 */
functionprocessFile(file) {
    const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
    const chunks = [];
    
    for (let i = 0; i < chunkCount; i++) {
        const start = i * CHUNK_SIZE;
        const end = Math.min(file.size, start + CHUNK_SIZE);
        chunks.push(file.slice(start, end));
    }
    return chunks;
}
2. 帶進度顯示的上傳邏輯
asyncfunctionuploadFile(file) {
    // 1. 初始化上傳
    const { data: uploadId } = await axios.post('/upload/init', {
        fileName: file.name,
        fileMd5: await calculateFileMD5(file) // 文件MD5計算
    });
    
    // 2. 分塊上傳
    const chunks = processFile(file);
    const total = chunks.length;
    let uploaded = 0;
    
    awaitPromise.all(chunks.map((chunk, index) => {
        const formData = new FormData();
        formData.append('chunk', chunk, `chunk_${index}`);
        formData.append('index', index);
        formData.append('uploadId', uploadId);
        formData.append('fileMd5', fileMd5);
        
        return axios.post('/upload/chunk', formData, {
            headers: {'Content-Type': 'multipart/form-data'},
            onUploadProgress: progress => {
                // 更新進度條
                const percent = ((uploaded * 100) / total).toFixed(1);
                updateProgress(percent);
            }
        }).then(() => uploaded++);
    }));
    
    // 3. 觸發合并
    const result = await axios.post('/upload/merge', {
        fileName: file.name,
        uploadId,
        fileMd5
    });
    
    alert(`上傳成功: ${result.data}`);
}

五、企業級優化方案

1. 斷點續傳實現

服務端增加檢查接口:

@GetMapping("/check/{fileMd5}/{uploadId}")
public ResponseEntity<List<Integer>> getUploadedChunks(
        @PathVariable String fileMd5,
        @PathVariable String uploadId) {
    
    Path chunkDir = Paths.get(CHUNK_DIR, fileMd5 + "_" + uploadId);
    if (!Files.exists(chunkDir)) {
        return ResponseEntity.ok(Collections.emptyList());
    }
    
    try {
        List<Integer> uploaded = Files.list(chunkDir)
                .map(p -> p.getFileName().toString())
                .filter(name -> name.startsWith("chunk_"))
                .map(name -> name.replace("chunk_", "").replace(".tmp", ""))
                .map(Integer::parseInt)
                .collect(Collectors.toList());
                
        return ResponseEntity.ok(uploaded);
    } catch (IOException e) {
        return ResponseEntity.status(500).body(Collections.emptyList());
    }
}

前端上傳前檢查:

const uploadedChunks = await axios.get(
    `/upload/check/${fileMd5}/${uploadId}`
);

chunks.map((chunk, index) => {
    if (uploadedChunks.includes(index)) {
        uploaded++; // 已上傳則跳過
        returnPromise.resolve(); 
    }
    // 執行上傳...
});
2. 分塊安全驗證

使用HmacSHA256確保分塊完整性:

@PostMapping("/chunk")
public ResponseEntity<?> uploadChunk(
        @RequestParam MultipartFile chunk,
        @RequestParam String sign // 前端生成的簽名
        ) {
    
    // 使用密鑰驗證簽名
    String secretKey = "your-secret-key";
    String serverSign = HmacUtils.hmacSha256Hex(secretKey, 
            chunk.getBytes());
    
    if (!serverSign.equals(sign)) {
        return ResponseEntity.status(403).body("簽名驗證失敗");
    }
    
    // 處理分塊...
}
3. 云存儲集成(MinIO示例)
@Configuration
publicclassMinioConfig{
    
    @Bean
    public MinioClient minioClient(){
        return MinioClient.builder()
                .endpoint("http://minio:9000")
                .credentials("minio-access", "minio-secret")
                .build();
    }
}

@Service
publicclassMinioUploadService{
    
    @Autowired
    private MinioClient minioClient;
    
    publicvoiduploadChunk(String bucket, 
                            String object, 
                            InputStream chunkStream, 
                            long length)throws Exception {
        
        minioClient.putObject(
            PutObjectArgs.builder()
                .bucket(bucket)
                .object(object)
                .stream(chunkStream, length, -1)
                .build()
        );
    }
}

六、性能測試對比

我們使用10GB文件進行測試,結果如下:

方案

平均上傳時間

內存占用

失敗重傳開銷

傳統上傳

3小時+

10GB+

100%

分塊上傳(單線程)

1.5小時

100MB

≈10%

分塊上傳(多線程)

20分鐘

100MB

<1%

七、最佳實踐建議

分塊大小選擇
  • 內網環境:10MB-20MB
  • 移動網絡:1MB-5MB
  • 廣域網:500KB-1MB
定時清理策略
@Scheduled(fixedRate = 24 * 60 * 60 * 1000) // 每日清理
publicvoidcleanTempFiles(){
    File tempDir = new File(CHUNK_DIR);
    // 刪除超過24小時的臨時目錄
    FileUtils.deleteDirectory(tempDir);
}
限流保護
spring:
  servlet:
    multipart:
      max-file-size:100MB# 單塊最大限制
      max-request-size:100MB

結語

Spring Boot實現文件分塊上傳解決了大文件傳輸的核心痛點,結合斷點續傳、分塊驗證和安全控制,可構建出健壯的企業級文件傳輸方案。本文提供的代碼可直接集成到生產環境,根據實際需求調整分塊大小和并發策略。

責任編輯:武曉燕 來源: 碼猿技術專欄
相關推薦

2025-07-02 00:00:00

2025-04-10 08:03:31

Spring系統

2020-08-14 11:01:32

數據Pandas文件

2025-07-03 07:41:34

2024-09-26 09:28:06

內存Spring

2021-11-26 22:01:26

Linux傳輸網絡

2021-06-07 00:03:31

HTTP大文件方案

2022-06-13 14:06:33

大文件上傳前端

2009-11-16 11:41:19

PHP上傳大文件

2025-05-06 01:21:00

C#內存SIMD

2009-07-21 15:38:31

2022-08-16 16:00:05

Python

2021-01-15 11:40:44

文件Java秒傳

2010-09-07 16:11:55

CSS Sprites

2022-08-12 22:53:32

HadoopHDFS分布式

2014-03-10 17:17:53

西數My Passport試用

2021-06-10 09:05:43

Linux命令大文件切割

2011-12-14 09:57:17

最快網絡傳輸速度186GB

2013-05-29 09:59:20

Java-RMI遠程調用

2009-12-07 09:45:23

PHP上傳大文件設置
點贊
收藏

51CTO技術棧公眾號

中文字幕日韩欧美精品高清在线| 欧美a级理论片| 日韩午夜电影av| 成人网18免费看| 亚洲综合激情| 欧美一级高清免费播放| 性视频一区二区三区| 国产在线一区观看| 国产精品永久在线| 伊人久久一区| 日韩亚洲电影在线| 中文字幕在线视频免费观看| 国产精品香蕉一区二区三区| 亚洲va男人天堂| 国产亚洲人成a在线v网站| 欧美色欧美亚洲另类二区| 色视频网站在线观看| 高清国产一区二区| 日韩久久不卡| 国产综合视频| 国产精品偷伦免费视频观看的| 亚洲热av色在线播放| 亚洲成人亚洲激情| 麻豆网在线观看| 欧美三级欧美成人高清www| 日本三级免费观看| 九一九一国产精品| 欧美在线视频二区| 亚洲人成在线影院| 91综合免费在线| 手机在线电影一区| 国产成人短视频| 哺乳一区二区三区中文视频 | 久久99精品久久久久久青青日本 | 亚洲青青一区| 亚洲精品福利视频| 性欧美猛交videos| 91精品国产高清一区二区三区 | 欧美 日韩精品| 高清在线不卡av| 在线看成人av电影| 精久久久久久久久久久| 秋霞在线观看一区二区三区| 宅男噜噜噜66国产日韩在线观看| 99久久99热这里只有精品 | 飘雪影院手机免费高清版在线观看 | 黄色网址入口| 91网上在线视频| 国产美女网站在线观看| 成人黄色小视频在线观看| 日韩video| 国产91富婆露脸刺激对白| 久久www视频| 99久久精品国产观看| 爱福利视频一区二区| 国产亚洲欧美日韩在线一区| 琪琪五月天综合婷婷| 日本一区二区在线看| 91av在线精品| 你懂的视频欧美| 国产精品免费久久久| 国产乱码精品一区二区三区不卡| 免费无码不卡视频在线观看| 久久久99免费| eeuss在线播放| 亚洲福利一区二区三区| 国内av一区二区三区| 欧美喷潮久久久xxxxx| 久久av色综合| 宅男66日本亚洲欧美视频| 另类视频一区二区三区| 国产精品久久精品| 伊人久久亚洲影院| 日本成人性视频| 中文乱码免费一区二区| 亚洲网站情趣视频| 精品久久久久久亚洲综合网| 日韩和的一区二在线| 国a精品视频大全| 一区二区国产在线| 中文字幕人成一区| 国产女主播视频一区二区| 婷婷亚洲一区二区三区| 亚洲第一黄色网| 综合激情久久| 国产91视觉| av在线不卡电影| 久艹在线视频| 精品欧美一区二区三区精品久久| 欧美高清hd| 国产日韩欧美精品| 26uuu精品一区二区| 老司机色在线视频| 日韩av综合网站| 成人免费看片39| 91社在线播放| 午夜久久福利影院| 成人直播视频| 91久久精品美女高潮| 成人综合婷婷国产精品久久蜜臀 | 欧美大陆国产| 91免费在线视频| 成人av在线播放网站| 美女网站在线| 亚洲欧美视频在线| 91精品国产福利在线观看麻豆| 最新av在线免费观看| 亚洲成av人片在线| jizz欧美| 麻豆亚洲一区| 亚洲欧美日韩电影| 超碰一区二区| 国产精品视频在线免费观看| 日本一区二区高清| 国产99在线| 成人免费高清完整版在线观看| 国产宾馆实践打屁股91| 久久久久久女乱国产| 色综合天天综合网国产成人网| 亚洲一区二区三区高清不卡| 男女羞羞视频教学| 中文字幕精品久久| 亚洲欧美日韩国产一区| 中文字幕视频在线观看| 欧美激情亚洲综合一区| 激情另类小说区图片区视频区| 性网站在线看| 热99精品里视频精品| 国产99久久久精品| gogo在线观看| 成人字幕网zmw| 亚洲欧洲日韩av| 精品亚洲a∨| 日本欧美黄网站| 91一区二区三区在线播放| 成入视频在线观看| 久久精品第九区免费观看 | 一区二区成人国产精品| 欧美日韩另类字幕中文| 欧美国产极品| 能在线观看的av| 亚洲人av在线影院| 久久午夜电影| 亚洲性线免费观看视频成熟| 成人ww免费完整版在线观看| 国产精品狼人色视频一区| 久久久久成人黄色影片| 成人网ww555视频免费看| 亚洲欧洲一二三| 91精品一区二区三区在线观看| 91精品国产成人观看| 波多野结衣在线中文| 91精品国产91久久久久久最新 | 久久精品视频va| 国产精品99久久久久久久女警| 污污网站在线看| 免费在线成人av电影| 在线电影院国产精品| 国产精品久久久久久模特 | 午夜精品久久99蜜桃的功能介绍| 在线播放国产区| 国产精品高潮呻吟久久av无限| 中文字幕中文乱码欧美一区二区| 北条麻妃在线一区二区免费播放 | 欧美人与牲禽动交com| 精品国产乱码久久久久久丨区2区| 亚洲电影一区二区三区| 91亚洲国产成人久久精品| 在线看片线路1| 国产日韩精品推荐| 欧美精品三级日韩久久| 久久久久欧美精品| sm久久捆绑调教精品一区| 婷婷视频在线播放| 色黄久久久久久| 国产欧美日本一区二区三区| 欧美调教视频| 一级片免费在线观看| 好看的日韩精品视频在线| 亚洲福利在线看| 成人国产精品免费观看| av日韩精品| 涩涩视频在线观看免费| 久久久影院一区二区三区 | 欧美日韩电影一区| 日韩av二区在线播放| 在线观看欧美日韩电影| 成人一对一视频| 欧美亚洲成人网| 色网站国产精品| 免费高清成人在线| 先锋影音网一区二区| 特黄特黄的视频| 久久人人九九| 国产亚洲欧美日韩美女| 97精品超碰一区二区三区| 露出调教综合另类| 成人一区二区不卡免费| 青青草原国产免费| 韩国19禁主播vip福利视频|