锋盈数科-知识库 Logo
首页
软件开发
计算机基础
Hello Halo
新手必读
关于本知识库
登录 →
锋盈数科-知识库 Logo
首页 软件开发 计算机基础 Hello Halo 新手必读 关于本知识库
登录
  1. 首页
  2. 软件开发
  3. Java实战:Spring Boot 实现文件断点下载

Java实战:Spring Boot 实现文件断点下载

0
  • 软件开发
  • 发布于 2024-08-16
  • 0 次阅读
黄健
黄健

本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net

本文将详细介绍如何在 Spring Boot 应用程序中实现文件断点下载功能。我们将深入探讨 HTTP 协议中的 Range 请求头以及如何使用 Spring Boot 中的 ResponseEntity 和 HttpHeaders 类来支持断点下载。

1. 引言

在现代的网络应用中,文件下载是一个常见的功能。特别是在大文件下载的场景中,如果网络不稳定或者下载过程被中断,用户希望能够从上次下载的位置继续下载,而不是重新开始。这种功能通常被称为 “断点下载”。
Spring Boot 是一个基于 Spring 框架的微服务开发框架,它简化了基于 Spring 的应用程序的开发和部署。在 Spring Boot 应用程序中,我们可以通过实现 HTTP 协议中的 Range 请求头来支持文件断点下载功能。

2. HTTP 断点下载原理

HTTP 协议中的 Range 请求头允许客户端指定下载资源的某个范围。服务器会返回指定范围内的数据,而不是整个资源。如果资源很大,客户端可以请求多个范围,然后将它们合并在一起。
Range 请求头的格式如下:

Range: bytes=start-end

其中,start 是资源中开始下载的字节,end 是结束的字节。如果省略 end,则表示下载到资源末尾。

3. Spring Boot 实现断点下载

在 Spring Boot 应用程序中,我们可以通过以下步骤实现文件断点下载功能:
3.1 创建 Controller 类
创建一个名为 FileDownloadController 的 Controller 类,用于处理文件下载请求。

import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@RestController
public class FileDownloadController {
    private final String filePath = "/path/to/your/file";
    @GetMapping("/download")
    public ResponseEntity<InputStreamResource> downloadFile() throws IOException {
        File file = new File(filePath);
        InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
        // 设置 HTTP 状态码为 206 Partial Content
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment; filename=" + file.getName());
        headers.add("Content-Range", "bytes 0-" + (file.length() - 1) + "/" + file.length());
        return ResponseEntity.status(206).headers(headers).body(resource);
    }
}

在这个示例中,我们首先创建了一个名为 filePath 的字符串变量,用于指定文件路径。然后,我们创建了一个 InputStreamResource 对象,用于包装文件输入流。接着,我们创建了一个 HttpHeaders 对象,并添加了 Content-Disposition 和 Content-Range 头部。最后,我们返回一个 ResponseEntity 对象,其中包含文件输入流资源和 HTTP 头部。

3.2 处理 Range 请求头
为了支持断点下载,我们需要处理 Range 请求头。在 Spring Boot 应用程序中,我们可以通过重写 HttpServletResponse 对象来实现这个功能。

import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
public class CustomHttpServletResponse extends HttpServletResponseWrapper {
    private final File file;
    private final long start;
    public CustomHttpServletResponse(HttpServletResponse response, File file, long start) {
        super(response);
        this.file = file;
        this.start = start;
    }
    @Override
@Override
public ServletOutputStream getOutputStream() throws IOException {
    ServletOutputStream outputStream = super.getOutputStream();
    FileInputStream inputStream = new FileInputStream(file);
    inputStream.skip(start);
    return new ServletOutputStream() {
        private OutputStream outputStream = outputStream.getOutputStream();
        @Override
        public void write(int b) throws IOException {
            outputStream.write(b);
        }
        @Override
        public void close() throws IOException {
            outputStream.close();
        }
    };
}

}

在这个示例中,我们创建了一个名为 `CustomHttpServletResponse` 的类,它继承自 `HttpServletResponseWrapper`。我们重写了 `getOutputStream` 方法,以返回一个自定义的 `ServletOutputStream` 对象。这个自定义的输出流从文件的指定位置开始读取数据,并将其写入 HTTP 响应中。
**3.3 修改 Controller 类**
现在我们需要修改 `FileDownloadController` 类,以使用我们的自定义响应包装器。
```java
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@RestController
public class FileDownloadController {
    private final String filePath = "/path/to/your/file";
    @GetMapping("/download")
    public void downloadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
        File file = new File(filePath);
        long start = 0;
        // 解析 Range 请求头
        String rangeHeader = request.getHeader("Range");
        if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
            String[] ranges = rangeHeader.substring("bytes=".length()).split("-");
            if (ranges.length == 2) {
                try {
                    start = Long.parseLong(ranges[0]);
                } catch (NumberFormatException e) {
                    // 忽略无效的 Range 值
                }
            }
        }
        // 设置 HTTP 状态码为 206 Partial Content
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        response.setHeader("Content-Type", "application/octet-stream");
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Range", "bytes " + start + "-" + (file.length() - 1) + "/" + file.length());
        // 使用自定义的响应包装器
        response.setContentLength((int) (file.length() - start));
        response.setHeader("Accept-Ranges", "bytes");
        new CustomHttpServletResponse(response, file, start).getOutputStream().close();
    }
}

在这个示例中,我们首先解析了 Range 请求头,并提取了开始的字节位置。然后,我们设置了 HTTP 状态码为 206 Partial Content,并添加了相应的头部信息。最后,我们使用自定义的响应包装器来处理文件下载请求。

4. 总结

本文详细介绍了如何在 Spring Boot 应用程序中实现文件断点下载功能。我们首先探讨了 HTTP 协议中的 Range 请求头以及如何使用 Spring Boot 中的 ResponseEntity 和 HttpHeaders 类来支持断点下载。然后,我们通过创建一个自定义的 HttpServletResponseWrapper 类,实现了从文件的指定位置开始下载的功能。
请注意,实际部署时,我们可能需要根据实际情况调整代码逻辑和配置,以及处理可能出现的异常情况。此外,对于生产环境,我们可能还需要考虑更多的错误处理和资源管理策略,例如优化代码性能和资源使用。
最后,如果您对 Spring Boot 实现文件断点下载功能或其他相关主题有更多的问题,欢迎在评论区留言讨论。

标签: #软件开发 1171 #JAVA 991 #Spring Boot 173
相关文章

万字:支付“核心系统”详解 2024-11-02 15:33

专栏作者:隐墨星辰 \| 主编:陈天宇宙 这篇文章也尝试化繁为简,探寻支付系统的本质,讲清楚在线支付系统最核心的一些概念和设计理念。 虽然支付行业已经过了风头最劲的时光,但跨境支付仍然在蓬勃发展,每年依然有很多新人进入这个行业,这篇文章尝试为这些刚入行的新人提供一点帮助。 文章只介绍一些支付行业十几

资深支付架构师视角:实战从问题定义到代码落地的完整套路 2024-11-02 15:33

前言 今天从一个实际案例入手,介绍站在架构师的角度,如何识别并定义问题,提炼需求,技术方案选型,再到详细设计,最后利用AI的能力协助写出核心的代码,验证与调优。 解决问题存在一定的模式,也可以称之为框架,总结出自己的思考和解题框架,以后再碰到同类型的问题就可以如庖丁解牛一样容易。 很多年前,我写代码

Spring 实现 3 种异步接口 2024-10-18 09:07

大家好,我是苏三~ 如何处理比较耗时的接口? 这题我熟,直接上异步接口,使用 Callable、WebAsyncTask 和 DeferredResult、CompletableFuture等均可实现。 但这些方法有局限性,处理结果仅返回单个值。在某些场景下,如果需要接口异步处理的同时,还持续不断地

重学SpringBoot3-集成Redis(五)之布隆过滤器 2024-10-08 11:24

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-集成Redis(五)之布隆过滤器 1. 什么是布隆过滤器? * 基本概念 适用场景 2. 使用 Redis 实现布隆过滤器 * 项目依赖 Redis 配置

设计模式第16讲——迭代器模式(Iterator) 2024-10-08 11:24

一、什么是迭代器模式 迭代器模式是一种行为型设计模式,它提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。简单地说,就是将遍历集合的责任封装到一个单独的对象中,我们可以按照特定的方式访问集合中的元素。 二、角色组成 抽象迭代器(Iterator):定义了遍历聚合对象所需的方法

vue2路由和vue3路由区别及原理 2024-10-08 11:24

一、Vue2 与 Vue3 路由的区别 1. 创建路由实例方式的不同 Vue 2 中,通过 Vue.use() 注册路由插件,并通过 new VueRouter() 来创建路由实例。 import Vue from 'vue';import VueRouter from 'vue-router';i

目录

IT 外包服务商

  • 意见投递
  • zyf6619

软件开发应用

主菜单

  • 首页
  • 软件开发
  • 计算机基础
  • Hello Halo
  • 新手必读
  • 关于本知识库
Copyright © 2024 your company All Rights Reserved. Powered by Halo.