Java实现大文件上传与断点续传的全过程

 更新时间:2026年01月21日 09:12:02   作者:Geek攻城猫  
本文介绍了如何使用Java(SpringBoot)实现高效、可靠的大型文件上传系统,包括分片上传、断点续传等核心设计思想和后端实现步骤,通过优化建议和进阶方案,进一步提升了用户体验和系统健壮性,需要的朋友可以参考下

在现代 Web 应用中,用户经常需要上传大型文件——如高清视频、设计图纸或数据库备份。然而,受限于网络稳定性、服务器内存和浏览器限制,直接上传大文件极易失败。为此,“分片上传 + 断点续传”成为业界标准解决方案。本文将深入讲解如何使用 Java(基于 Spring Boot) 实现高效、可靠的大文件上传系统。

一、为什么需要断点续传?

  • 网络不稳定:上传过程中断后,无需从头开始。
  • 节省带宽与时间:仅重传失败或未传的分片。
  • 提升用户体验:支持上传进度显示、暂停/恢复。
  • 避免服务器压力:避免一次性加载整个大文件到内存。

二、核心设计思想

1. 文件分片(Chunking)

将一个大文件按固定大小(如 2MB)切分为多个小块(chunks),每个块独立上传。

2. 唯一标识

使用文件内容的 MD5 值 作为唯一 ID,既可识别文件,又能避免重复上传相同内容。

3. 分片管理

  • 后端为每个文件创建临时目录,按序号存储分片。
  • 提供接口查询“已上传分片列表”,实现断点检测。

4. 合并与清理

所有分片收齐后,按顺序合并成完整文件,并清理临时数据。

三、后端实现(Spring Boot)

1. 项目依赖(Maven)

<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("/api/upload")
public class ResumableUploadController {

    private static final String TEMP_DIR = "uploads/temp/";
    private static final String FINAL_DIR = "uploads/final/";

    /**
     * 检查哪些分片已上传(用于断点续传)
     */
    @GetMapping("/check")
    public Set<Integer> checkUploadedChunks(@RequestParam String fileMd5) {
        Set<Integer> uploaded = new HashSet<>();
        Path tempPath = Paths.get(TEMP_DIR, fileMd5);
        if (Files.exists(tempPath)) {
            try (Stream<Path> stream = Files.list(tempPath)) {
                stream.forEach(p -> {
                    String name = p.getFileName().toString();
                    if (name.matches("\\d+")) {
                        uploaded.add(Integer.parseInt(name));
                    }
                });
            } catch (IOException e) {
                // 日志记录
            }
        }
        return uploaded;
    }

    /**
     * 上传单个分片
     */
    @PostMapping("/chunk")
    public ResponseEntity<?> uploadChunk(
            @RequestParam String fileMd5,
            @RequestParam int chunkIndex,
            @RequestParam MultipartFile chunk) {

        try {
            Path tempDir = Paths.get(TEMP_DIR, fileMd5);
            Files.createDirectories(tempDir);
            Path chunkFile = tempDir.resolve(String.valueOf(chunkIndex));
            chunk.transferTo(chunkFile.toFile());
            return ResponseEntity.ok().build();
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 合并所有分片为完整文件
     */
    @PostMapping("/merge")
    public ResponseEntity<?> mergeChunks(
            @RequestParam String fileMd5,
            @RequestParam String fileName,
            @RequestParam int totalChunks) {

        try {
            Path finalPath = Paths.get(FINAL_DIR, fileName);
            Files.createDirectories(finalPath.getParent());

            try (OutputStream out = Files.newOutputStream(finalPath)) {
                for (int i = 0; i < totalChunks; i++) {
                    Path chunk = Paths.get(TEMP_DIR, fileMd5, String.valueOf(i));
                    if (!Files.exists(chunk)) {
                        return ResponseEntity.badRequest()
                                .body("Missing chunk: " + i);
                    }
                    byte[] data = Files.readAllBytes(chunk);
                    out.write(data);
                }
            }

            // 清理临时分片
            FileUtils.deleteDirectory(new File(TEMP_DIR + fileMd5));

            return ResponseEntity.ok(Map.of("success", true, "path", finalPath.toString()));
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
}

注意:实际项目中应加入文件名校验、权限控制、异常日志等。

四、前端配合逻辑(简要)

前端需完成以下步骤:

  1. 计算文件 MD5(推荐使用 spark-md5 库)。
  2. 调用 /check 接口 获取已上传分片索引。
  3. 循环上传未完成的分片,每个请求携带:
    • fileMd5
    • chunkIndex
    • 分片 Blob 数据
  4. 全部上传完成后,调用 /merge 触发合并
// 示例:上传一个分片
const uploadChunk = async (fileMd5, index, blob) => {
  const formData = new FormData();
  formData.append('fileMd5', fileMd5);
  formData.append('chunkIndex', index);
  formData.append('chunk', blob);
  await fetch('/api/upload/chunk', { method: 'POST', body: formData });
};

五、关键优化建议

优化点说明
MD5 计算前端计算可避免重复上传;若安全要求高,后端也可二次校验。
并发上传允许同时上传多个分片(如 3~5 个),提升速度。
超时清理定时任务删除 24 小时未合并的临时分片,防止磁盘占满。
限流与鉴权防止恶意上传,限制单用户上传频率和总大小。
进度反馈前端根据已传分片数实时更新进度条。

六、进阶方案

1. 使用 TUS 协议

TUS 是一个开源的 Resumable Upload 标准。Java 社区有 tus-java-server 实现,开箱即用,支持跨平台、跨语言。

2. 对接云存储

阿里云 OSS、腾讯云 COS、AWS S3 等均提供 分片上传 API。可将分片直接上传至云存储,后端仅负责协调,大幅降低服务器负载。

七、总结

通过“分片上传 + 断点续传”,我们不仅能可靠地处理 GB 级文件,还能显著提升用户体验和系统健壮性。虽然实现细节较多,但核心逻辑清晰:切分 → 上传 → 校验 → 合并

在实际项目中,建议结合业务需求选择自研或集成成熟方案。对于高并发、高可靠场景,优先考虑云厂商的分片上传能力;对于内部系统或定制化需求,本文提供的 Java 实现可作为坚实基础。

以上就是Java实现大文件上传与断点续传的全过程的详细内容,更多关于Java大文件上传与断点续传的资料请关注脚本之家其它相关文章!

相关文章

  • 深入Java Final

    深入Java Final

    本篇文章,小编将为大家介绍Java Final,有需要的朋友可以参考一下
    2013-04-04
  • Java求素数和最大公约数的简单代码示例

    Java求素数和最大公约数的简单代码示例

    这篇文章主要介绍了Java求素数和最大公约数的简单代码示例,其中作者创建的Fraction类可以用来进行各种分数运算,需要的朋友可以参考下
    2015-09-09
  • 详解Java 中 RMI 的使用

    详解Java 中 RMI 的使用

    这篇文章主要介绍了Java 中 RMI 的使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-05-05
  • springboot使用spring-data-jpa操作MySQL数据库

    springboot使用spring-data-jpa操作MySQL数据库

    这篇文章主要介绍了springboot使用spring-data-jpa操作MySQL数据库,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Spring Boot Web 开发注解篇

    Spring Boot Web 开发注解篇

    在 Spring Boot 快速入门中,只要在 pom.xml 加入了 spring-boot-starter-web 依赖,即可快速开发 web 应用。下文给大家详细介绍了spring boot web 开发注解,感兴趣的朋友参考下吧
    2017-08-08
  • Java Gradle项目中的资源正确获取方式

    Java Gradle项目中的资源正确获取方式

    这篇文章主要介绍了Java Gradle项目中的资源正确获取方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • 详解poi+springmvc+springjdbc导入导出excel实例

    详解poi+springmvc+springjdbc导入导出excel实例

    本篇文章主要介绍了poi+springmvc+springjdbc导入导出excel实例,非常具有实用价值,需要的朋友可以参考下。
    2017-01-01
  • Java实现多用户注册登录的幸运抽奖

    Java实现多用户注册登录的幸运抽奖

    这篇文章主要为大家详细介绍了Java实现多用户注册登录的幸运抽奖,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • Spring Boot利用Docker快速部署项目的完整步骤

    Spring Boot利用Docker快速部署项目的完整步骤

    这篇文章主要给大家介绍了关于Spring Boot利用Docker快速部署项目的完整步骤,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-07-07
  • 解决java压缩图片透明背景变黑色的问题

    解决java压缩图片透明背景变黑色的问题

    这篇文章主要介绍了解决java压缩图片透明背景变黑色的问题,需要的朋友可以参考下
    2014-04-04

最新评论