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

vue+springboot上傳大文件的實現(xiàn)示例

 更新時間:2023年04月24日 10:25:35   作者:相與還  
本文主要介紹了vue+springboot上傳大文件的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

眾所周知,上傳大文件是一件很麻煩的事情,假如一條路走到黑,直接一次性把文件上傳上去,對于小文件是可以這樣做,但是對于大文件可能會出現(xiàn)網(wǎng)絡問題,請求響應時長等等導致文件上傳失敗,那么這次來教大家如何用vue+srpingboot項目上傳大文件

邏輯

需要做大文件上傳應該考慮到如下邏輯:

  • 大文件上傳一般需要將文件切片(chunk)上傳,然后再將所有切片合并為完整的文件??梢园匆韵逻壿嬤M行實現(xiàn):
  • 前端在頁面中選擇要上傳的文件,并使用Blob.slice方法對文件進行切片,一般每個切片大小為固定值(比如5MB),并記錄總共有多少個切片。
  • 將切片分別上傳到后端服務,可以使用XMLHttpRequest或Axios等庫發(fā)送Ajax請求。對于每個切片,需要包含三個參數(shù):當前切片索引(從0開始)、切片總數(shù)、切片文件數(shù)據(jù)。
  • 后端服務接收到切片后,保存到指定路徑下的臨時文件中,并記錄已上傳的切片索引和上傳狀態(tài)。如果某個切片上傳失敗,則通知前端重傳該切片。
  • 當所有切片都上傳成功后,后端服務讀取所有切片內(nèi)容并將其合并為完整的文件??梢允褂胘ava.io.SequenceInputStream和BufferedOutputStream來實現(xiàn)文件合并。
  • 最后返回文件上傳成功的響應結果給前端即可。

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
    <input type="file" id="fileInput">
    <button onclick="upload()">Upload</button>
    <script>
        function upload() {
            let file = document.getElementById("fileInput").files[0];
            let chunkSize = 5 * 1024 * 1024; // 切片大小為5MB
            let totalChunks = Math.ceil(file.size / chunkSize); // 計算切片總數(shù)
            let index = 0;
            while (index < totalChunks) {
                let chunk = file.slice(index * chunkSize, (index + 1) * chunkSize);
                let formData = new FormData();
                formData.append("file", chunk);
                formData.append("index", index);
                formData.append("totalChunks", totalChunks);
                // 發(fā)送Ajax請求上傳切片
                $.ajax({
                    url: "/uploadChunk",
                    type: "POST",
                    data: formData,
                    processData: false,
                    contentType: false,
                    success: function () {
                        if (++index >= totalChunks) {
                            // 所有切片上傳完成,通知服務端合并文件
                            $.post("/mergeFile", {fileName: file.name}, function () {
                                alert("Upload complete!");
                            })
                        }
                    }
                });
            }
        }
    </script>
</body>
</html>

后端

controller層:

@RestController
public class FileController {

    @Value("${file.upload-path}")
    private String uploadPath;

    @PostMapping("/uploadChunk")
    public void uploadChunk(@RequestParam("file") MultipartFile file,
                            @RequestParam("index") int index,
                            @RequestParam("totalChunks") int totalChunks) throws IOException {
        // 以文件名+切片索引號為文件名保存切片文件
        String fileName = file.getOriginalFilename() + "." + index;
        Path tempFile = Paths.get(uploadPath, fileName);
        Files.write(tempFile, file.getBytes());
        // 記錄上傳狀態(tài)
        String uploadFlag = UUID.randomUUID().toString();
        redisTemplate.opsForList().set("upload:" + fileName, index, uploadFlag);
        // 如果所有切片已上傳,則通知合并文件
        if (isAllChunksUploaded(fileName, totalChunks)) {
            sendMergeRequest(fileName, totalChunks);
        }
    }

    @PostMapping("/mergeFile")
    public void mergeFile(String fileName) throws IOException {
        // 所有切片均已成功上傳,進行文件合并
        List<File> chunkFiles = new ArrayList<>();
        for (int i = 0; i < getTotalChunks(fileName); i++) {
            String chunkFileName = fileName + "." + i;
            Path tempFile = Paths.get(uploadPath, chunkFileName);
            chunkFiles.add(tempFile.toFile());
        }
        Path destFile = Paths.get(uploadPath, fileName);
        try (OutputStream out = Files.newOutputStream(destFile);
             SequenceInputStream seqIn = new SequenceInputStream(Collections.enumeration(chunkFiles));
             BufferedInputStream bufIn = new BufferedInputStream(seqIn)) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bufIn.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        }
        // 清理臨時文件和上傳狀態(tài)記錄
        for (int i = 0; i < getTotalChunks(fileName); i++) {
            String chunkFileName = fileName + "." + i;
            Path tempFile = Paths.get(uploadPath, chunkFileName);
            Files.deleteIfExists(tempFile);
            redisTemplate.delete("upload:" + chunkFileName);
        }
    }

    private int getTotalChunks(String fileName) {
        // 根據(jù)文件名獲取總切片數(shù)
        return Objects.requireNonNull(Paths.get(uploadPath, fileName).toFile().listFiles()).length;
    }

    private boolean isAllChunksUploaded(String fileName, int totalChunks) {
        // 判斷所有切片是否已都上傳完成
        List<String> uploadFlags = redisTemplate.opsForList().range("upload:" + fileName, 0, -1);
        return uploadFlags != null && uploadFlags.size() == totalChunks;
    }

    private void sendMergeRequest(String fileName, int totalChunks) {
        // 發(fā)送合并文件請求
        new Thread(() -> {
            try {
                URL url = new URL("http://localhost:8080/mergeFile");
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
                OutputStream out = conn.getOutputStream();
                String query = "fileName=" + fileName;
                out.write(query.getBytes());
                out.flush();
                out.close();
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
                while (br.readLine() != null) ;
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
}

其中,file.upload-path為文件上傳的保存路徑,可以在application.properties或application.yml中進行配置。同時需要添加RedisTemplate的Bean以便記錄上傳狀態(tài)。

RedisTemplate配置

如果需要使用RedisTemplate,需要引入下方的包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

同時在yml配置redis的信息

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0

然后在自己的類中這樣使用

@Component
public class myClass {

? ? @Autowired
? ? private RedisTemplate<String, Object> redisTemplate;

? ? public void set(String key, Object value) {
? ? ? ? redisTemplate.opsForValue().set(key, value);
? ? }

? ? public Object get(String key) {
? ? ? ? return redisTemplate.opsForValue().get(key);
? ? }
}

注意事項

  • 需要控制每次上傳的切片大小,以兼顧上傳速度和穩(wěn)定性,避免占用過多服務器資源或因網(wǎng)絡不穩(wěn)定而導致上傳失敗。
  • 切片上傳存在先后順序,需要保證所有切片都上傳完成后再進行合并,否則可能會出現(xiàn)文件不完整或者文件合并錯誤等情況。
  • 上傳完成后需要及時清理臨時文件,避免因為占用過多磁盤空間而導致服務器崩潰??梢栽O置一個定期任務來清理過期的臨時文件。

結語

到此這篇關于vue+springboot上傳大文件的實現(xiàn)示例的文章就介紹到這了,更多相關vue springboot上傳大文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Vue中訪問指定鏈接并解析頁面內(nèi)容的完整指南

    Vue中訪問指定鏈接并解析頁面內(nèi)容的完整指南

    在現(xiàn)代Web開發(fā)中,經(jīng)常需要從其他網(wǎng)頁獲取并解析內(nèi)容,本文將詳細介紹如何在Vue項目中實現(xiàn)這一功能,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-03-03
  • 詳解Vue 事件驅(qū)動和依賴追蹤

    詳解Vue 事件驅(qū)動和依賴追蹤

    本篇文章主要介紹了詳解Vue 事件驅(qū)動和依賴追蹤 ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • vue接入下載文件接口問題

    vue接入下載文件接口問題

    這篇文章主要介紹了vue接入下載文件接口問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • vue-cli腳手架搭建方式(vue腳手架方式搭建)

    vue-cli腳手架搭建方式(vue腳手架方式搭建)

    這篇文章主要介紹了vue-cli(vue腳手架方式搭建),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • vue設置默認首頁的操作

    vue設置默認首頁的操作

    這篇文章主要介紹了vue設置默認首頁的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • vue-cli腳手架引入彈出層layer插件的幾種方法

    vue-cli腳手架引入彈出層layer插件的幾種方法

    layer.js(mobile)是一個小巧方便的彈出層插件,在之前的apicloud項目中被大量使用,但最近對apicloud的IDE、非常不友好的文檔和極低的開發(fā)效率深感厭煩,決定棄用然后轉(zhuǎn)向Vue開發(fā)。這篇文章主要介紹了vue-cli腳手架引入彈出層layer插件的幾種方法,需要的朋友可以參考下
    2019-06-06
  • 手寫vue無限滾動指令的詳細過程

    手寫vue無限滾動指令的詳細過程

    今天在移動端項目中遇見一個需求,需要數(shù)據(jù)無限滾動,所以下面這篇文章主要給大家介紹了關于手寫vue無限滾動指令的詳細過程,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • 淺析Vue3中Excel下載模板并導入數(shù)據(jù)功能的實現(xiàn)

    淺析Vue3中Excel下載模板并導入數(shù)據(jù)功能的實現(xiàn)

    這篇文章主要為大家詳細介紹了Vue3中的Excel數(shù)據(jù)管理,即下載模板并導入數(shù)據(jù)功能的實現(xiàn),文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下
    2024-05-05
  • 使用vue腳手架(vue-cli)搭建一個項目詳解

    使用vue腳手架(vue-cli)搭建一個項目詳解

    這篇文章主要介紹了vue腳手架(vue-cli)搭建項目,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-05-05
  • element表格組件實現(xiàn)右鍵菜單的功能

    element表格組件實現(xiàn)右鍵菜單的功能

    本文主要介紹了element表格組件實現(xiàn)右鍵菜單的功能,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03

最新評論

绥芬河市| 丰台区| 澄迈县| 黑水县| 云龙县| 泊头市| 静安区| 贡山| 陇川县| 镇平县| 温州市| 任丘市| 汶上县| 临漳县| 新邵县| 双江| 鲁甸县| 饶河县| 南岸区| 阿拉善盟| 砚山县| 环江| 湘阴县| 曲松县| 台前县| 名山县| 汽车| 屏南县| 梧州市| 大姚县| 沧源| 丘北县| 甘洛县| 郁南县| 伊吾县| 肃宁县| 策勒县| 蒙山县| 瑞金市| 大渡口区| 衡阳市|