SpringBoot实现文件下载的限速功能

 更新时间:2024年07月03日 11:13:40   作者:shy好好学习  
在SpringBoot项目中,实现文件下载的限速功能可以有效控制服务器带宽的占用,并防止单个用户消耗过多的资源,本文将通过具体的代码示例和详细的流程解释,介绍如何在SpringBoot项目中实现文件下载的限速功能,需要的朋友可以参考下

前言

在文件下载过程中,如果不加以控制,可能会导致服务器带宽被单个或少数用户占用,影响其他用户的访问体验。通过实现文件下载的限速,可以平衡带宽资源的使用,确保所有用户都有良好的下载体验。

实现思路

为了实现文件下载的限速,我们需要以下几个关键步骤:

  • 创建一个工具类,用于限制下载速率。
  • 在控制器中使用该工具类处理文件下载请求。
  • 使用StreamingResponseBody实现流式响应,确保大文件可以逐步传输。

代码实现

步骤1:创建限速工具类

首先,我们创建一个限速工具类RateLimiter,该类包含一个方法limitDownloadSpeed,用于限制下载速率。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @desc: 文件工具类
 * @author: shy
 * @date: 2024/06/28 11:27
 */
public class FileUtil {

    private static final int BUFFER_SIZE = 1024;

    /**
     * 文件下载限速
     *
     * @param in             输入流
     * @param out            输出流
     * @param bytesPerSecond 每秒允许下载的字节数
     * @throws IOException
     */
    public static void limitDownloadSpeed(InputStream in, OutputStream out, int bytesPerSecond) throws IOException {
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead;
        long bytesSent = 0;
        long startTime = System.currentTimeMillis();
        try {
            while ((bytesRead = in.read(buffer)) != -1) {
                // 将数据写入输出流
                out.write(buffer, 0, bytesRead);
                bytesSent += bytesRead;

                if (bytesSent >= bytesPerSecond) {
                    long elapsedTime = System.currentTimeMillis() - startTime;
                    if (elapsedTime < 1000) {
                        // 如果时间少于1秒,则休眠剩余时间
                        Thread.sleep(1000 - elapsedTime);
                    }
                    // 重置已发送字节计数和开始时间
                    bytesSent = 0;
                    startTime = System.currentTimeMillis();
                }
            }
        } catch (InterruptedException e) {
            // 恢复线程的中断状态
            Thread.currentThread().interrupt();
            throw new IOException("Thread was interrupted", e);
        }
    }
}

解释

  • BUFFER_SIZE:定义缓冲区大小。
  • limitDownloadSpeed:通过try-with-resources管理InputStream,根据设定的速率读取数据并写入输出流,控制传输速率。

步骤2:修改文件下载控制器

接下来,我们在控制器中使用StreamingResponseBody来实现文件下载,并调用限速工具类的方法。

import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import com.shy.admin.common.annotation.WithoutLogin;
import com.shy.common.utils.FileUtil;

/**
 * @desc: 文件下载Controller
 * @author: shy
 * @date: 2024/06/28 10:48
 */
@RestController
@RequestMapping("/file")
public class FileController {

    // 每秒允许下载的字节数(例如100KB/s)
    private static final int BYTES_PER_SECOND = 1024 * 100; 

    @WithoutLogin
    @GetMapping("/download/{filename}")
    public ResponseEntity<StreamingResponseBody> downloadFile(@PathVariable String filename) {
        // 获取要下载的文件
        File file = new File("D:\\tools\\" + filename);
        // 使用 StreamingResponseBody 实现流式响应体
        StreamingResponseBody responseBody = outputStream -> {
            try (InputStream inputStream = Files.newInputStream(file.toPath())) {
                // 调用限速方法
                FileUtil.limitDownloadSpeed(inputStream, outputStream, BYTES_PER_SECOND);
            }
        };
        // 返回 ResponseEntity,包含响应头和流式响应体
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName())
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .contentLength(file.length())
                .body(responseBody);
    }
}

解释

  • StreamingResponseBody:实现流式响应体,用于处理大文件的逐步传输。
  • responseBody:通过lambda表达式实现StreamingResponseBodywriteTo方法,在方法中使用try-with-resources管理InputStream,并调用RateLimiter的方法实现限速。

工作流程

  1. 请求处理:当客户端发送下载请求时,Spring 调用控制器方法downloadFile
  2. 创建 StreamingResponseBody:控制器方法创建StreamingResponseBody实例。
  3. 返回 ResponseEntity:控制器方法返回包含StreamingResponseBodyResponseEntity,并设置适当的响应头(如Content-DispositionContent-Type)。
  4. 调用 writeTo 方法:Spring 在准备向客户端发送响应时,调用StreamingResponseBodywriteTo方法,并传入与客户端连接的OutputStream
  5. 写入数据writeTo方法中,从文件输入流读取数据,并通过RateLimiter方法将数据写入OutputStream,同时控制传输速率。

总结

通过以上步骤,我们成功在SpringBoot项目中实现了文件下载的限速功能。核心思路是通过一个限速工具类控制数据传输速率,并使用StreamingResponseBody实现流式响应,确保大文件可以逐步传输。这种设计既能有效控制带宽资源的使用,又能提供良好的用户下载体验。

以上就是SpringBoot实现文件下载的限速功能的详细内容,更多关于SpringBoot文件下载限速的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot项目的配置文件中设置server.port不生效问题

    SpringBoot项目的配置文件中设置server.port不生效问题

    这篇文章主要介绍了SpringBoot项目的配置文件中设置server.port不生效问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Java中@valid和@Validated注解的使用详解

    Java中@valid和@Validated注解的使用详解

    这篇文章主要介绍了Java中@valid和@Validated注解的使用详解,@Validated可以用在类型、方法和方法参数上,但是不能用在成员属性(字段)上,不支持嵌套检测,@Valid可以用在方法、构造函数、方法参数和成员属性(字段)上,支持嵌套检测,需要的朋友可以参考下
    2024-01-01
  • IDEA maven项目依赖无法解析问题

    IDEA maven项目依赖无法解析问题

    这篇文章主要介绍了IDEA maven项目依赖无法解析问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • JavaWeb实现学生信息管理系统(2)

    JavaWeb实现学生信息管理系统(2)

    这篇文章主要介绍了JavaWeb实现学生信息管理系统的第二篇,实现学生管理系统的查找和添加功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 基于log4j2.properties踩坑与填坑

    基于log4j2.properties踩坑与填坑

    这篇文章主要介绍了log4j2.properties踩坑与填坑方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • java常见的字符串拼接方式总结

    java常见的字符串拼接方式总结

    这篇文章主要为大家详细介绍了java中常见的字符串拼接方式,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-09-09
  • Java数据结构之线段树中的懒操作详解

    Java数据结构之线段树中的懒操作详解

    对于线段树,若要求对区间中的所有点都进行更新,可以引入懒操作。懒操作包括区间更新和区间查询操作。本文将通过一个示例和大家详细聊聊线段树中的懒操作,需要的可以参考一下
    2022-10-10
  • springboot时间格式化的五种方法总结(解决后端传给前端的时间显示不一致)

    springboot时间格式化的五种方法总结(解决后端传给前端的时间显示不一致)

    这篇文章主要给大家介绍了关于springboot时间格式化的五种方法,文中介绍的方法解决了后端传给前端的时间显示不一致,文中通过图文以及代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • spring源码下载、编译、debug的详细教程

    spring源码下载、编译、debug的详细教程

    这篇文章主要介绍了spring源码下载、编译、debug的详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Java生成日期时间存入Mysql数据库的实现方法

    Java生成日期时间存入Mysql数据库的实现方法

    本文主要介绍了Java生成日期时间存入Mysql数据库的实现方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03

最新评论