下载文件的ResponseEntity使用方法详解

一、使用方法介绍

在Web应用程序中,我们常常需要提供文件的下载功能。Spring提供了一个ResponseEntity类,可以方便地下载文件。ResponseEntity类表示整个HTTP响应(即响应头和响应体),可以设置响应的状态码、响应头信息和响应体内容。通过设置响应头信息,可以指定下载文件的文件名、文件大小和文件类型等信息。

示例:下载csv文件

@GetMapping("/downloadCsv")
public ResponseEntity downloadCsv() throws IOException {
    String filename = "demo.csv";
    String path = "file/demo.csv";
    File file = new File(path);
    byte[] bytes = FileCopyUtils.copyToByteArray(file);
    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
    headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
    headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
    return new ResponseEntity(bytes, headers, HttpStatus.OK);
}

代码中,先获取要下载的文件,将文件以字节流的形式读取到byte数组中,然后设置响应头信息,并将byte数组、响应头和响应状态码封装到ResponseEntity对象中返回。

二、下载文件的注意事项

1、在设置下载文件名时,需要进行URL编码。如果直接设置中文文件名,会导致下载的文件名乱码。

示例:

String filename = "中文文件名.csv";
String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + encodedFilename);

2、在读取文件时,要注意设置字节流的缓存大小,避免大文件导致内存溢出。

示例:

FileInputStream fileInputStream = new FileInputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = fileInputStream.read(buffer)) != -1) {
    outputStream.write(buffer, 0, len);
}
fileInputStream.close();

3、如果下载的文件较大,建议使用分块下载功能,分块下载可以有效地减小服务器和客户端的负载,并提高下载速度。

三、下载速度的优化

下载文件的速度影响了用户的体验,如何优化下载速度是我们需要考虑的一个问题。以下是一些优化方式:

1、启用Gzip压缩:可以启用Gzip压缩,可以减小传输文件的大小,从而提高下载速度。

示例:

@GetMapping("/downloadCsv")
public ResponseEntity downloadCsv() throws IOException {
    // 省略获取文件的代码
    byte[] bytes = FileCopyUtils.copyToByteArray(file);
    byte[] gzippedBytes = gzipCompress(bytes);
    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
    headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
    headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(gzippedBytes.length));
    headers.add(HttpHeaders.CONTENT_ENCODING, "gzip");
    return new ResponseEntity(gzippedBytes, headers, HttpStatus.OK);
}

private byte[] gzipCompress(byte[] bytes) throws IOException {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
    gzipOutputStream.write(bytes);
    gzipOutputStream.close();
    return byteArrayOutputStream.toByteArray();
}

2、启用CDN加速:可以使用CDN加速服务,将文件存储到CDN服务器上,利用CDN服务器的高速网络,加速文件的下载。

3、使用断点续传:断点续传可以将文件分成多个部分,分别进行下载,如果下载中发生网络异常,可以从已下载的部分继续下载,避免重复下载已下载的部分,从而提高下载速度。

示例:

@GetMapping("/downloadBigFile")
public void downloadBigFile(HttpServletRequest request, HttpServletResponse response) throws Exception {
    String filePath = "file/demo.mp4";
    File file = new File(filePath);
    String fileName = file.getName();
    long fileLength = file.length();
    long startPos = 0;
    long endPos = fileLength - 1;
    long contentLength = endPos - startPos + 1;
    response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
    response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
    response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
    byte[] buffer = new byte[1024 * 1024];
    RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
    if(request.getHeader(HttpHeaders.RANGE) == null) {
        response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength));
        randomAccessFile.seek(startPos);
        OutputStream outputStream = response.getOutputStream();
        while (contentLength > 0) {
            int read = randomAccessFile.read(buffer, 0, (int) Math.min(buffer.length, contentLength));
            contentLength -= read;
            outputStream.write(buffer, 0, read);
            outputStream.flush();
        }
        randomAccessFile.close();
        outputStream.close();
        return;
    }
    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
    String range = request.getHeader(HttpHeaders.RANGE);
    range = range.replaceAll("bytes=", "").trim();
    String[] ranges = range.split("-");
    if(!StringUtils.isEmpty(ranges[0])) {
        startPos = Long.parseLong(ranges[0]);
    }
    if(ranges.length > 1 && !StringUtils.isEmpty(ranges[1])) {
        endPos = Long.parseLong(ranges[1]);
    }
    contentLength = endPos - startPos + 1;
    response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
    response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + startPos + "-" + endPos + "/" + fileLength);
    randomAccessFile.seek(startPos);
    OutputStream outputStream = response.getOutputStream();
    while (contentLength > 0) {
        int read = randomAccessFile.read(buffer, 0, (int) Math.min(buffer.length, contentLength));
        contentLength -= read;
        outputStream.write(buffer, 0, read);
        outputStream.flush();
    }
    randomAccessFile.close();
    outputStream.close();
}

代码中,首先判断是否支持断点续传,如果支持,则解析HTTP请求头中的Range字段,计算出下载的起始位置和结束位置,设置响应头,将文件的指定部分发送给客户端。如果不支持断点续传,则直接将整个文件发送给客户端。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/193384.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-01 15:01
下一篇 2024-12-01 15:01

相关推荐

  • vue下载无后缀名的文件被加上后缀.txt,有后缀名的文件下载正常问题的解决

    本文旨在解决vue下载无后缀名的文件被加上后缀.txt,有后缀名的文件下载正常的问题,提供完整的代码示例供参考。 一、分析问题 首先,需了解vue中下载文件的情况。一般情况下,我们…

    编程 2025-04-29
  • Python中init方法的作用及使用方法

    Python中的init方法是一个类的构造函数,在创建对象时被调用。在本篇文章中,我们将从多个方面详细讨论init方法的作用,使用方法以及注意点。 一、定义init方法 在Pyth…

    编程 2025-04-29
  • 如何在Java中拼接OBJ格式的文件并生成完整的图像

    OBJ格式是一种用于表示3D对象的标准格式,通常由一组顶点、面和纹理映射坐标组成。在本文中,我们将讨论如何将多个OBJ文件拼接在一起,生成一个完整的3D模型。 一、读取OBJ文件 …

    编程 2025-04-29
  • Python程序文件的拓展

    Python是一门功能丰富、易于学习、可读性高的编程语言。Python程序文件通常以.py为文件拓展名,被广泛应用于各种领域,包括Web开发、机器学习、科学计算等。为了更好地发挥P…

    编程 2025-04-29
  • 为什么用cmd运行Java时需要在文件内打开cmd为中心

    在Java开发中,我们经常会使用cmd在命令行窗口运行程序。然而,有时候我们会发现,在运行Java程序时,需要在文件内打开cmd为中心,这让很多开发者感到疑惑,那么,为什么会出现这…

    编程 2025-04-29
  • Python中读入csv文件数据的方法用法介绍

    csv是一种常见的数据格式,通常用于存储小型数据集。Python作为一种广泛流行的编程语言,内置了许多操作csv文件的库。本文将从多个方面详细介绍Python读入csv文件的方法。…

    编程 2025-04-29
  • Python zipfile解压文件乱码处理

    本文主要介绍如何在Python中使用zipfile进行文件解压的处理,同时详细讨论在解压文件时可能出现的乱码问题的各种解决办法。 一、zipfile解压文件乱码问题的根本原因 在P…

    编程 2025-04-29
  • Python将矩阵存为CSV文件

    CSV文件是一种通用的文件格式,在统计学和计算机科学中非常常见,一些数据分析工具如Microsoft Excel,Google Sheets等都支持读取CSV文件。Python内置…

    编程 2025-04-29
  • Python如何导入py文件

    Python是一种开源的高级编程语言,因其易学易用和强大的生态系统而备受青睐。Python的import语句可以帮助用户将一个模块中的代码导入到另一个模块中,从而实现代码的重用。本…

    编程 2025-04-29
  • Python合并多个相同表头文件

    对于需要合并多个相同表头文件的情况,我们可以使用Python来实现快速的合并。 一、读取CSV文件 使用Python中的csv库读取CSV文件。 import csv with o…

    编程 2025-04-29

发表回复

登录后才能评论