成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot 實戰:文件上傳之秒傳、斷點續傳、分片上傳

開發 前端
在日常開發中,文件上傳的場景多種多樣。比如,在線教育平臺上的視頻資源上傳,社交平臺上的圖片分享,以及企業內部的知識文檔管理等。

文件上傳功能幾乎是每個 Web 應用不可或缺的一部分。無論是個人博客中的圖片上傳,還是企業級應用中的文檔管理,文件上傳都扮演著至關重要的角色。今天,松哥和大家來聊聊文件上傳中的幾個高級玩法——秒傳、斷點續傳和分片上傳。

一 文件上傳的常見場景

在日常開發中,文件上傳的場景多種多樣。比如,在線教育平臺上的視頻資源上傳,社交平臺上的圖片分享,以及企業內部的知識文檔管理等。這些場景對文件上傳的要求也各不相同,有的追求速度,有的注重穩定性,還有的需要考慮文件大小和安全性。因此,針對不同需求,我們有了秒傳、斷點續傳和分片上傳等解決方案。

二 秒傳、斷點上傳與分片上傳

秒傳

秒傳,顧名思義,就是幾乎瞬間完成文件上傳的過程。其實現原理是通過計算文件的哈希值(如 MD5 或 SHA-1),然后將這個唯一的標識符發送給服務器。如果服務器上已經存在相同的文件,則直接返回成功信息,避免了重復上傳。這種方式不僅節省了帶寬,也大大提高了用戶體驗。

斷點續傳

斷點續傳是指在網絡不穩定或者用戶主動中斷上傳后,能夠從上次中斷的地方繼續上傳,而不需要重新開始整個過程。這對于大文件上傳尤為重要,因為它可以有效防止因網絡問題導致的上傳失敗,同時也能節約用戶的流量和時間。

分片上傳

分片上傳則是將一個大文件分割成多個小塊分別上傳,最后再由服務器合并成完整的文件。這種做法的好處是可以并行處理多個小文件,提高上傳效率;同時,如果某一部分上傳失敗,只需要重傳這一部分,不影響其他部分。

三 秒傳實戰

后端實現

在 SpringBoot 項目中,我們可以使用 MessageDigest 類來計算文件的 MD5 值,然后檢查數據庫中是否存在該文件。

@RestController
@RequestMapping("/file")
public class FileController {
    @Autowired
    FileService fileService;

    @PostMapping("/upload1")
    public ResponseEntity<String> secondUpload(@RequestParam(value = "file",required = false) MultipartFile file,@RequestParam(required = false,value = "md5") String md5) {
        try {
            // 檢查數據庫中是否已存在該文件
            if (fileService.existsByMd5(md5)) {
                return ResponseEntity.ok("文件已存在");
            }
            // 保存文件到服務器
            file.transferTo(new File("/path/to/save/" + file.getOriginalFilename()));
            // 保存文件信息到數據庫
            fileService.save(new FileInfo(file.getOriginalFilename(), DigestUtils.md5DigestAsHex(file.getInputStream())));
            return ResponseEntity.ok("上傳成功");
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("上傳失敗");
        }
    }
}

前端調用

前端可以通過 JavaScript 的 FileReader API 讀取文件內容,通過 spark-md5 計算 MD5 值,然后發送給后端進行校驗。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>秒傳</title>
    <script src="spark-md5.js"></script>
</head>
<body>
<input type="file" id="fileInput" />
<button onclick="startUpload()">開始上傳</button>
<hr>
<script>
    async function startUpload() {
        const fileInput = document.getElementById('fileInput');
        const file = fileInput.files[0];
        if (!file) {
            alert("請選擇文件");
            return;
        }

        const md5 = await calculateMd5(file);
        const formData = new FormData();
        formData.append('md5', md5);

        const response = await fetch('/file/upload1', {
            method: 'POST',
            body: formData
        });

        const result = await response.text();
        if (response.ok) {
            if (result != "文件已存在") {
                // 開始上傳文件
            }
        } else {
            console.error("上傳失敗: " + result);
        }
    }

    function calculateMd5(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onloadend = () => {
                const spark = new SparkMD5.ArrayBuffer();
                spark.append(reader.result);
                resolve(spark.end());
            };
            reader.onerror = () => reject(reader.error);
            reader.readAsArrayBuffer(file);
        });
    }
</script>
</body>
</html>

前端分為兩個步驟:

  1. 計算文件的 MD5 值,計算之后發送給服務端確定文件是否存在。
  2. 如果文件已經存在,則不需要繼續上傳文件;如果文件不存在,則開始上傳文件,上傳文件和 MD5 校驗請求類似,上面的案例代碼中我就沒有重復演示了,松哥在書里和之前的課程里都多次講過文件上傳,這里不再啰嗦。

四 分片上傳實戰

分片上傳關鍵是在前端對文件切片,比如一個 10MB 的文件切為 10 份,每份 1MB。每次上傳的時候,需要多一個參數記錄當前上傳的文件切片的起始位置。

比如一個 10MB 的文件,切為 10 份,每份 1MB,那么:

  • 第 0 片,從 0 開始,一共是 1024*1024 個字節。
  • 第 1 片,從 1024*1024 開始,一共是 1024*1024 個字節。
  • 第 2 片...

把這個搞懂,后面的代碼就好理解了。

后端實現

private static final String UPLOAD_DIR = System.getProperty("user.home") + "/uploads/";
/**
 * 上傳文件到指定位置
 *
 * @param file 上傳的文件
 * @param start 文件開始上傳的位置
 * @return ResponseEntity<String> 上傳結果
 */
@PostMapping("/upload2")
public ResponseEntity<String> resumeUpload(@RequestParam("file") MultipartFile file, @RequestParam("start") long start,@RequestParam("fileName") String fileName) {
    try {
        File directory = new File(UPLOAD_DIR);
        if (!directory.exists()) {
            directory.mkdirs();
        }
        File targetFile = new File(UPLOAD_DIR + fileName);
        RandomAccessFile randomAccessFile = new RandomAccessFile(targetFile, "rw");
        FileChannel channel = randomAccessFile.getChannel();
        channel.position(start);
        channel.transferFrom(file.getResource().readableChannel(), start, file.getSize());
        channel.close();
        randomAccessFile.close();
        return ResponseEntity.ok("上傳成功");
    } catch (Exception e) {
        System.out.println("上傳失敗: "+e.getMessage());
        return ResponseEntity.status(500).body("上傳失敗");
    }
}

后端每次處理的時候,需要先設置文件的起始位置。

前端調用

前端需要將文件切分成多個小塊,然后依次上傳。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>分片示例</title>
</head>
<body>
    <input type="file" id="fileInput" />
    <button onclick="startUpload()">開始上傳</button>

    <script>
        async function startUpload() {
            const fileInput = document.getElementById('fileInput');
            const file = fileInput.files[0];
            if (!file) {
                alert("請選擇文件");
                return;
            }

            const filename = file.name;
            let start = 0;

            uploadFile(file, start);
        }

        async function uploadFile(file, start) {
            const chunkSize = 1024 * 1024; // 每個分片1MB
            const total = Math.ceil(file.size / chunkSize);

            for (let i = 0; i < total; i++) {
                const chunkStart = start + i * chunkSize;
                const chunkEnd = Math.min(chunkStart + chunkSize, file.size);
                const chunk = file.slice(chunkStart, chunkEnd);

                const formData = new FormData();
                formData.append('file', chunk);
                formData.append('start', chunkStart);
                formData.append('fileName', file.name);

                const response = await fetch('/file/upload2', {
                    method: 'POST',
                    body: formData
                });

                const result = await response.text();
                if (response.ok) {
                    console.log(`分片 ${i + 1}/${total} 上傳成功`);
                } else {
                    console.error(`分片 ${i + 1}/${total} 上傳失敗: ${result}`);
                    break;
                }
            }
        }
    </script>
</body>
</html>

五 斷點續傳實戰

斷點續傳的技術原理類似于分片上傳。

當文件已經上傳了一部分之后,斷了需要重新開始上傳。

那么我們的思路是這樣的:

  1. 前端先發送一個請求,檢查要上傳的文件在服務端是否已經存在,如果存在,目前大小是多少。
  2. 前端根據已經存在的大小,繼續上傳文件即可。

后端案例

先來看后端檢查的接口,如下:

@GetMapping("/check")
public ResponseEntity<Long> checkFile(@RequestParam("filename") String filename) {
    File file = new File(UPLOAD_DIR + filename);
    if (file.exists()) {
        return ResponseEntity.ok(file.length());
    } else {
        return ResponseEntity.ok(0L);
    }
}

如果文件存在,則返回已經存在的文件大小。

如果文件不存在,則返回 0,表示前端從頭開始上傳該文件。

前端調用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>斷點續傳示例</title>
</head>
<body>
<input type="file" id="fileInput"/>
<button onclick="startUpload()">開始上傳</button>

<script>
    async function startUpload() {
        const fileInput = document.getElementById('fileInput');
        const file = fileInput.files[0];
        if (!file) {
            alert("請選擇文件");
            return;
        }

        const filename = file.name;
        let start = await checkFile(filename);

        uploadFile(file, start);
    }

    async function checkFile(filename) {
        const response = await fetch(`/file/check?filename=${filename}`);
        const start = await response.json();
        return start;
    }

    async function uploadFile(file, start) {
        const chunkSize = 1024 * 1024; // 每個分片1MB
        const total = Math.ceil((file.size - start) / chunkSize);

        for (let i = 0; i < total; i++) {
            const chunkStart = start + i * chunkSize;
            const chunkEnd = Math.min(chunkStart + chunkSize, file.size);
            const chunk = file.slice(chunkStart, chunkEnd);

            const formData = new FormData();
            formData.append('file', chunk);
            formData.append('start', chunkStart);
            formData.append('fileName', file.name);

            const response = await fetch('/file/upload2', {
                method: 'POST',
                body: formData
            });

            const result = await response.text();
            if (response.ok) {
                console.log(`分片 ${i + 1}/${total} 上傳成功`);
            } else {
                console.error(`分片 ${i + 1}/${total} 上傳失敗: ${result}`);
                break;
            }
        }
    }
</script>
</body>
</html>

這個案例實際上是一個斷點續傳+分片上傳的案例,相關知識點并不難,小伙伴們可以自行體會下。

六 總結

好了,以上就是關于文件上傳中秒傳、斷點續傳和分片上傳的實戰分享。通過這些技術的應用,我們可以極大地提升文件上傳的效率和穩定性,改善用戶體驗。希望各位小伙伴在自己的項目中也能靈活運用這些技巧,解決實際問題。


責任編輯:武曉燕 來源: 江南一點雨
相關推薦

2021-01-15 11:40:44

文件Java秒傳

2022-06-15 09:01:45

大文件秒傳分片上傳

2017-08-08 08:45:44

前端文件斷點續傳

2023-06-20 19:57:13

2011-03-04 16:41:57

FileZilla

2020-04-02 20:07:17

前端vuenote.js

2023-03-09 12:04:38

Spring文件校驗

2021-01-18 05:19:11

數字指紋

2022-08-05 08:40:37

架構

2013-07-22 14:02:17

iOS開發ASIHTTPRequ

2024-07-02 10:18:18

2009-08-28 15:38:49

C#實現斷點續傳

2025-06-17 08:39:43

2017-12-20 15:11:48

iOS緩存文件斷點機制

2010-04-07 11:09:53

2011-03-01 14:12:12

FreebsdProftpd

2009-11-16 10:49:43

PHP上傳文件代碼

2025-04-10 08:03:31

Spring系統

2013-03-25 14:13:23

iOSASIHTTPRequ

2009-11-16 14:38:36

PHP上傳文件代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产亚洲精品久久久久久豆腐 | 亚洲97 | 亚洲视频免费 | 青草视频在线 | 啪一啪在线视频 | 国产一区二区三区视频 | 天天干 夜夜操 | 午夜视频大全 | 亚洲人成网亚洲欧洲无码 | 欧美激情综合 | 精品国产乱码久久久久久蜜柚 | 国产精品高清一区二区三区 | 欧美高清一区 | 国产精品美女久久久免费 | 中文字幕蜜臀av | 一区二区三区四区在线视频 | 欧美一区视频 | 荷兰欧美一级毛片 | 欧美一区二区免费 | 天天综合亚洲 | 中文字幕免费在线 | 亚洲一区二区三区在线 | 久久精品国产99国产精品 | 欧美精品在线免费观看 | 羞羞视频网站免费观看 | 福利一区二区 | 国产精品久久久久久久久久免费看 | 亚洲国产日韩一区 | 国产亚洲一区二区三区在线观看 | 九色在线观看 | 日日天天 | 国产成人福利 | 国内精品视频免费观看 | 欧美在线a | 日日日日日日bbbbb视频 | 新超碰97 | 特级生活片| 成人精品鲁一区一区二区 | 国产色婷婷精品综合在线播放 | 免费精品视频 | 欧美一区不卡 |