自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring Boot超大文件上傳的正確方式

開發(fā) 前端
分片上傳文件指的是將大文件分割成較小的部分(即分片),然后依次或并行地將這些分片上傳到服務(wù)器的過程。一旦所有分片都上傳完畢,服務(wù)器會將它們合并以重新創(chuàng)建出原始文件。

環(huán)境:SpringBoot3.4.0

1. 簡介

文件上傳功能是個非常常見的需求,它允許用戶將本地計(jì)算機(jī)上的文件通過網(wǎng)絡(luò)傳輸?shù)竭h(yuǎn)程服務(wù)器。然而,如果不對大文件的上傳進(jìn)行適當(dāng)?shù)目刂?,很可能會對服?wù)器造成以下不良影響:

  • 網(wǎng)絡(luò)不穩(wěn)定性:大文件上傳耗時較長,期間網(wǎng)絡(luò)的任何不穩(wěn)定性都可能導(dǎo)致上傳失敗,需要重新上傳整個文件,這不僅耗時而且效率低下。
  • 帶寬限制:在帶寬有限的網(wǎng)絡(luò)環(huán)境中,大文件上傳可能會占用大量帶寬,導(dǎo)致其他網(wǎng)絡(luò)活動受阻,影響用戶體驗(yàn)。
  • 服務(wù)器負(fù)擔(dān):一次性處理大量數(shù)據(jù)會給服務(wù)器帶來巨大負(fù)擔(dān),尤其是在高并發(fā)的情況下,可能導(dǎo)致服務(wù)器響應(yīng)緩慢或崩潰。

如何解決大文件上傳的問題呢?接下來,我們將介紹一種有效的解決方案——分片上傳。

分片上傳文件指的是將大文件分割成較小的部分(即分片),然后依次或并行地將這些分片上傳到服務(wù)器的過程。一旦所有分片都上傳完畢,服務(wù)器會將它們合并以重新創(chuàng)建出原始文件。

分片上傳原理:

  • 在客戶端將文件分割成較小的分片
  • 將每個分片單獨(dú)上傳到服務(wù)器
  • 所有分片上傳完成后,利用這些分片重新構(gòu)建出原始文件

接下來,我們將通過Spring Boot 3與Vue 3的結(jié)合來實(shí)現(xiàn)大文件的分片上傳功能。

2. 實(shí)戰(zhàn)案例

2.1 前端頁面

我們僅為了演示文件的分片上傳功能,所以設(shè)計(jì)的頁面非常簡潔,僅包含三個按鈕,頁面效果如下所示:圖片

前端代碼

<el-upload ref="upload" class="upload-demo"
  :limit="1" :auto-upload="false" :http-request="uploadFile">
  <template #trigger>
    <el-button type="primary" style="margin-right: 10px;">選擇文件</el-button>
  </template>
  <el-button class="ml-3" type="success" @click="submitUpload">
    上傳文件
  </el-button>
</el-upload>
<el-button class="ml-3" type="primary" @click="mergeFile">合并文件</el-button>

JavaScript代碼

<script setup name="upload">
  import { ref } from 'vue'


  const upload = ref('')
  let fileName = ''
  /**拆分文件,這里估計(jì)將文件每2M進(jìn)行拆分*/
  const uploadFileInChunks = file => {
    const chunkSize = 1024 * 1024 * 2
    let start = 0
    let chunkIndex = 0


    while (start < file.size) {
      const chunk = file.slice(start, start + chunkSize)
      console.log(chunk)
      fileName = file.name
      uploadChunk(chunk, chunkIndex, fileName)
      start += chunkSize
      chunkIndex++
    }
  }
  /**對每一個拆分的文件進(jìn)行上傳;這就就成了小文件上傳*/
  const uploadChunk = (chunk, chunkIndex, fileName) => {
    const formData = new FormData()
    formData.append('chunk', chunk)
    formData.append('chunkIndex', chunkIndex)
    formData.append('fileName', fileName)


    fetch('http://localhost:8080/upload-chunk', {
      method: 'POST',
      body: formData
    }).then(resp => {
      console.log(resp)
    })
  }
  const uploadFile = (opt) => {
    uploadFileInChunks(opt.file)
  }
  const submitUpload = () => {
    upload.value.submit()
  }
  /**合并文件*/
  const mergeFile = () => {
    const formData = new FormData()
    formData.append('fileName', fileName)
    fetch('http://localhost:8080/merge-chunks', {
      method: 'POST',
      body: formData
    }).then(resp => {
      console.log(resp)
    })
  }
</script>

前端代碼還是非常簡單的;其核心就是拿到上傳文件的File對象,然后對文件進(jìn)行拆分。

2.2 文件上傳接口

@RestController
public class ChunkController {
  private static final String TEMP_DIR = "d:\\upload\\";
  @PostMapping("/upload-chunk")
  public ResponseEntity<String> uploadChunk(
      @RequestParam("chunk") MultipartFile chunk,
      @RequestParam("chunkIndex") int chunkIndex, 
      @RequestParam("fileName") String fileName) throws IOException {
    File dir = new File(TEMP_DIR + fileName);
    if (!dir.exists()) {
      dir.mkdirs();
    }
    File chunkFile = new File(dir, "chunk_" + chunkIndex);
    try (OutputStream os = new FileOutputStream(chunkFile)) {
      os.write(chunk.getBytes());
    }
    return ResponseEntity.ok("Chunk " + chunkIndex + " uploaded successfully.");
  }
}

這里非常的簡單與我們平時的文件上傳一模一樣。

接下來,我們就可以進(jìn)行文件的上傳了

圖片圖片

這里選擇了一個25MB大小的文件,點(diǎn)擊上傳后控制臺輸出:

圖片圖片

這里拆分成了13個小文件進(jìn)行上傳。

最終,后臺服務(wù)上的文件如下:

圖片

以上傳的文件名創(chuàng)建了目錄,存分塊后的小文件。

文件上傳完成后,最后我們就要對這些文件進(jìn)行合并處理了。

2.3 合并文件接口

@RestController
public class ChunkController {
  private static final String TEMP_DIR = "d:\\upload\\";
  private static final String TARGET_DIR = "d:\\upload\\result\\";
  
  @PostMapping("/merge-chunks")
  public ResponseEntity<String> mergeChunks(
      @RequestParam("fileName") String fileName) throws IOException {
    File dir = new File(TEMP_DIR + fileName);
    File mergedFile = new File(TARGET_DIR + fileName);
    try (OutputStream os = new FileOutputStream(mergedFile)) {
      for (int i = 0, len = dir.listFiles().length; i < len; i++) {
        File chunkFile = new File(dir, "chunk_" + i);
        Files.copy(chunkFile.toPath(), os);
        chunkFile.delete();
      }
    }
    dir.delete();
    return ResponseEntity.ok("文件合并完成");
  }
}

這里就是遍歷目錄中的所有文件,然后按照順序?qū)懭氲揭粋€目標(biāo)文件中即可。這樣我們就完成了文件的合并。

圖片

到此我們實(shí)現(xiàn)了文件的分塊上傳功能。

責(zé)任編輯:武曉燕 來源: Springboot全家桶實(shí)戰(zhàn)案例源碼
相關(guān)推薦

2009-12-07 09:45:23

PHP上傳大文件設(shè)置

2025-04-10 08:03:31

Spring系統(tǒng)

2021-01-25 14:10:49

Spring BootVueJava

2021-09-15 16:20:02

Spring BootFilterJava

2009-11-16 11:41:19

PHP上傳大文件

2022-06-13 14:06:33

大文件上傳前端

2021-05-10 07:33:10

Java開源工具

2021-01-15 12:02:25

java 大文件工具

2025-03-11 00:55:00

Spring停機(jī)安全

2023-03-09 12:04:38

Spring文件校驗(yàn)

2009-07-21 15:38:31

2021-03-11 14:16:47

Spring Boo開發(fā)腳手架

2022-05-17 10:45:55

項(xiàng)目VueElementUI

2024-12-26 11:01:22

2021-01-15 11:40:44

文件Java秒傳

2024-01-23 08:47:13

BeanSpring加載方式

2023-11-01 15:07:51

環(huán)境配置方式

2024-07-02 10:18:18

2009-07-20 16:09:39

2020-04-02 20:07:17

前端vuenote.js
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號