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

高效應(yīng)對(duì)內(nèi)存溢出!Spring Boot 3.3 大文件處理全攻略

開(kāi)發(fā) 前端
本文深入探討了如何在 Spring Boot3.3 中實(shí)現(xiàn)大文件分塊處理與上傳,通過(guò)分塊的方式降低內(nèi)存壓力,并且結(jié)合 jQuery 前端實(shí)現(xiàn)了分塊提交,利用 Bootstrap 進(jìn)行用戶(hù)上傳狀態(tài)的提示。

在現(xiàn)代應(yīng)用程序中,處理大文件已成為一項(xiàng)常見(jiàn)需求,例如視頻上傳、數(shù)據(jù)遷移和日志分析等。然而,當(dāng)處理超過(guò)內(nèi)存容量的大文件時(shí),可能會(huì)導(dǎo)致內(nèi)存溢出(OutOfMemoryError)的問(wèn)題,影響應(yīng)用程序的穩(wěn)定性和性能。傳統(tǒng)的文件處理方式通常將整個(gè)文件加載到內(nèi)存中,這在處理大文件時(shí)顯然不可行。

為了解決這一挑戰(zhàn),我們需要采用高效的文件處理策略,例如分塊處理和流式讀取。這些方法可以有效降低內(nèi)存占用,提高文件處理的效率。本文將深入探討如何在 Spring Boot 3.3 中實(shí)現(xiàn)大文件的高效處理,包括分塊上傳、服務(wù)端分塊保存,以及前端使用 jQuery 和 Bootstrap 實(shí)現(xiàn)分塊上傳的流程。

分塊處理的流程介紹

分塊處理是一種將大文件拆分為多個(gè)小塊,逐個(gè)傳輸和處理的技術(shù)。其主要流程如下:

  1. 前端文件分塊: 在客戶(hù)端(瀏覽器)將大文件按照一定大小(如 1MB)進(jìn)行拆分,生成多個(gè)文件塊。
  2. 分塊上傳: 前端逐個(gè)將文件塊通過(guò) HTTP 請(qǐng)求上傳到服務(wù)器,可以使用 AJAX 異步提交。
  3. 服務(wù)端接收并保存: 服務(wù)器接收到文件塊后,按順序?qū)⑵浔4娴脚R時(shí)文件或直接寫(xiě)入目標(biāo)文件,使用流式寫(xiě)入方式,避免占用過(guò)多內(nèi)存。
  4. 合并文件塊: 如果在臨時(shí)目錄保存,待所有文件塊上傳完成后,服務(wù)器將所有文件塊按序合并為最終的完整文件。
  5. 返回上傳結(jié)果: 服務(wù)器將上傳結(jié)果以 JSON 格式返回給前端,前端根據(jù)結(jié)果進(jìn)行相應(yīng)的提示和處理。

運(yùn)行效果:

圖片圖片

若想獲取項(xiàng)目完整代碼以及其他文章的項(xiàng)目源碼,且在代碼編寫(xiě)時(shí)遇到問(wèn)題需要咨詢(xún)交流,歡迎加入下方的知識(shí)星球。

項(xiàng)目結(jié)構(gòu)

src
├── main
│   ├── java
│   │   └── com.icoderoad.largefile
│   │       ├── config
│   │       │   └── FileUploadProperties.java   // 讀取配置文件的類(lèi)
│   │       ├── controller
│   │       │   └── FileUploadController.java   // 文件上傳控制器
│   │       ├── service
│   │       │   └── FileProcessingService.java  // 文件處理服務(wù)(含分塊處理邏輯)
│   ├── resources
│   │   ├── application.yml                      // 配置文件
│   │   ├── templates
│   │   │   └── index.html                      // 文件上傳頁(yè)面
└─── └───pom.xml                                  // 項(xiàng)目依賴(lài)配置

POM 文件配置

在 pom.xml 中引入必要的依賴(lài),包括 Spring Boot、Thymeleaf、文件上傳和 JSON 處理等。

<?xml versinotallow="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.icoderoad</groupId>
	<artifactId>largefile-upload</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>largefile-upload</name>
	<description>Demo project for Spring Boot</description>
	
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Thymeleaf 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- 文件上傳相關(guān)依賴(lài) -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

YAML 配置文件 application.yml

在 application.yml 中配置文件上傳相關(guān)屬性。

server:
  port: 8080

spring:
  servlet:
    multipart:
      max-file-size: 200MB
      max-request-size: 210MB

file-upload:
  upload-dir: /tmp/uploads
  chunk-size: 1MB # 分塊大小

讀取配置類(lèi) FileUploadProperties.java

package com.icoderoad.largefile.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "file-upload")
public class FileUploadProperties {
    private String uploadDir;
    private String chunkSize; // 分塊大小
}

文件處理服務(wù) FileProcessingService.java

在服務(wù)層中實(shí)現(xiàn)分塊處理的邏輯,包括接收文件塊并按順序保存。

package com.example.largefile.service;

import com.example.largefile.config.FileUploadProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class FileProcessingService {

    private final FileUploadProperties fileUploadProperties;

    // 保存單個(gè)文件塊
    public void saveFileChunk(MultipartFile file, String filename, int chunkIndex) throws Exception {
        // 獲取上傳目錄
        String uploadDir = fileUploadProperties.getUploadDir();
        Path uploadPath = Paths.get(uploadDir);

        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
        }

        // 保存文件塊到臨時(shí)文件
        File outputFile = new File(uploadDir + File.separator + filename + ".part" + chunkIndex);
        try (InputStream inputStream = file.getInputStream();
             FileOutputStream outputStream = new FileOutputStream(outputFile)) {
            byte[] buffer = new byte[1024 * 1024]; // 1MB 緩沖區(qū)
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
    }

    // 合并文件塊
    public void mergeFileChunks(String filename, int totalChunks) throws Exception {
        String uploadDir = fileUploadProperties.getUploadDir();
        File outputFile = new File(uploadDir + File.separator + filename);
        try (FileOutputStream outputStream = new FileOutputStream(outputFile, true)) {
            for (int i = 0; i < totalChunks; i++) {
                File chunkFile = new File(uploadDir + File.separator + filename + ".part" + i);
                try (FileInputStream inputStream = new FileInputStream(chunkFile)) {
                    byte[] buffer = new byte[1024 * 1024];
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                }
                // 刪除塊文件
                chunkFile.delete();
            }
        }
    }
}

文件上傳控制器 FileUploadController.java

控制器接收分塊文件,并在所有塊接收完成后調(diào)用服務(wù)合并文件。返回 JSON 格式的數(shù)據(jù),提示前端上傳進(jìn)度和狀態(tài)。

package com.icoderoad.largefile.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.icoderoad.largefile.service.FileProcessingService;

import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/upload")
public class FileUploadController {

    private final FileProcessingService fileProcessingService;

    @PostMapping("/chunk")
    public Map<String, Object> handleFileChunkUpload(
            @RequestParam("file") MultipartFile file,
            @RequestParam("filename") String filename,
            @RequestParam("chunkIndex") int chunkIndex,
            @RequestParam("totalChunks") int totalChunks) {
        
        Map<String, Object> response = new HashMap<>();
        try {
            fileProcessingService.saveFileChunk(file, filename, chunkIndex);
            response.put("status", "chunk_uploaded");
            response.put("chunkIndex", chunkIndex);

            // 如果是最后一個(gè)塊,進(jìn)行文件合并
            if (chunkIndex == totalChunks - 1) {
                fileProcessingService.mergeFileChunks(filename, totalChunks);
                response.put("status", "file_uploaded");
            }
        } catch (Exception e) {
            response.put("status", "error");
            response.put("message", e.getMessage());
        }
        return response;
    }
}

前端頁(yè)面 index.html

前端頁(yè)面使用 jQuery 分塊上傳文件,并使用 Bootstrap 的提示組件顯示上傳進(jìn)度和結(jié)果。

在 src/main/resources/templates 目錄下創(chuàng)建 index.html 文件:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>大文件上傳</title>
    <link rel="stylesheet" >
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>

<div class="container">
    <h2 class="mt-5">大文件上傳</h2>

    <form id="uploadForm">
        <div class="form-group">
            <label for="file">選擇文件</label>
            <input type="file" class="form-control-file" id="file" name="file">
        </div>
        <button type="button" id="uploadBtn" class="btn btn-primary">上傳</button>
    </form>

    <div id="uploadProgress" class="alert alert-info mt-3" style="display:none;"></div>
</div>

<script>
    $(function() {
        $('#uploadBtn').on('click', function() {
            var file = $('#file')[0].files[0];
            if (!file) {
                alert('請(qǐng)選擇文件進(jìn)行上傳');
                return;
            }

            var chunkSize = 1024 * 1024; // 1MB
            var totalChunks = Math.ceil(file.size / chunkSize);

            for (var i = 0; i < totalChunks; i++) {
                var chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
                var formData = new FormData();
                formData.append('file', chunk);
                formData.append('filename', file.name);
                formData.append('chunkIndex', i);
                formData.append('totalChunks', totalChunks);

                $.ajax({
                    url: '/upload/chunk',
                    type: 'POST',
                    data: formData,
                    processData: false,
                    contentType: false,
                    success: function (response) {
                        if (response.status === 'chunk_uploaded') {
                            $('#uploadProgress').show().text('已上傳塊: ' + (response.chunkIndex + 1) + '/' + totalChunks);
                        } else if (response.status === 'file_uploaded') {
                            $('#uploadProgress').removeClass('alert-info').addClass('alert-success').text('文件上傳完成');
                        }
                    }
                });
            }
        });
    });
</script>

</body>
</html>

總結(jié)

本文深入探討了如何在 Spring Boot3.3 中實(shí)現(xiàn)大文件分塊處理與上傳,通過(guò)分塊的方式降低內(nèi)存壓力,并且結(jié)合 jQuery 前端實(shí)現(xiàn)了分塊提交,利用 Bootstrap 進(jìn)行用戶(hù)上傳狀態(tài)的提示。通過(guò)這種方式,既提高了系統(tǒng)的穩(wěn)定性,也增強(qiáng)了用戶(hù)體驗(yàn)。在實(shí)際應(yīng)用中,這種技術(shù)可以廣泛應(yīng)用于音視頻文件上傳、日志文件處理等場(chǎng)景,確保系統(tǒng)在處理大數(shù)據(jù)時(shí)依然能高效、穩(wěn)定地運(yùn)行。

責(zé)任編輯:武曉燕 來(lái)源: 路條編程
相關(guān)推薦

2024-08-26 09:15:55

RedissonMyBatisSpring

2025-04-18 03:00:00

2013-06-08 11:13:00

Android開(kāi)發(fā)XML解析

2013-04-15 10:48:16

Xcode ARC詳解iOS ARC使用

2024-05-07 09:01:21

Queue 模塊Python線程安全隊(duì)列

2010-04-23 14:04:23

Oracle日期操作

2009-07-04 11:05:48

Linux安全攻略

2021-04-23 20:59:02

ThreadLocal內(nèi)存

2010-09-08 17:46:13

2014-03-19 17:22:33

2009-10-19 15:20:01

家庭綜合布線

2009-12-14 14:32:38

動(dòng)態(tài)路由配置

2009-02-20 11:43:22

UNIXfish全攻略

2025-01-21 08:10:00

2022-07-25 11:33:48

Python大文件

2009-12-17 16:15:00

CCNA640-810

2010-08-25 14:36:02

DHCP服務(wù)器

2019-06-27 11:47:21

Wordpress容器化HTTPS

2024-10-25 15:25:42

2020-11-23 15:21:12

Linux環(huán)境變量
點(diǎn)贊
收藏

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