当前位置: 代码网 > it编程>编程语言>Java > spring文件下载的四种方式及对比分析

spring文件下载的四种方式及对比分析

2025年08月13日 Java 我要评论
方式一:通过responseentity 方式来下载@apioperation(value = "下载数据文档模板")@getmapping("/download-template/1")public

方式一:通过responseentity 方式来下载

@apioperation(value = "下载数据文档模板")
@getmapping("/download-template/1")
public responseentity<resource> downloadfile01(httpservletrequest request) {
    try {
        resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
        // 检查资源是否存在
        if (resource.exists() || resource.isreadable()) {
            return responseentity.ok()
                    .header(httpheaders.content_length, string.valueof(resource.contentlength()))
                    .header(httpheaders.content_disposition, "attachment; filename=" + encodefilename(request, resource.getfilename()))
                    .contenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream))
                    .body(resource);
        } else {
            return responseentity.notfound().build();
        }
    } catch (exception e) {
        log.error("文件模板下载失败!", e);
        return responseentity.internalservererror().build();
    }
}
/**
 * 根据浏览器类型编码文件名
 * @param request 请求对象
 * @param filename 原始文件名
 * @return 编码后的文件名
 */
private static string encodefilename(httpservletrequest request, string filename) {
    string useragent = request.getheader("user-agent");
    // 处理ie及edge浏览器
    if (useragent.contains("msie") || useragent.contains("trident") || useragent.contains("edge")) {
        return cn.hutool.core.net.urlencoder.createdefault().encode(filename, standardcharsets.utf_8);
    }
    // 其他浏览器使用iso-8859-1编码
    return new string(filename.getbytes(standardcharsets.utf_8), standardcharsets.iso_8859_1);
}

方式二:通过responseentity 方式来下载

@apioperation(value = "下载数据文档模板")
@getmapping("/download-template/2")
public responseentity<streamingresponsebody> downloadfile02(httpservletrequest request) {
    try {
        resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
        streamingresponsebody body = outputstream -> {
            fileutil.writetostream(resource.getfile(), outputstream);
        };
        // 检查资源是否存在
        if (resource.exists() || resource.isreadable()) {
            return responseentity.ok()
                    .header(httpheaders.content_length, string.valueof(resource.contentlength()))
              			//	省略 encodefilename 方法
                    .header(httpheaders.content_disposition, "attachment; filename=" + encodefilename(request, resource.getfilename()))
                    .contenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream))
                    .body(body);
        } else {
            return responseentity.notfound().build();
        }
    } catch (exception e) {
        log.error("文件模板下载失败!", e);
        return responseentity.internalservererror().build();
    }
}

方式三:通过servlet原生下载

@apioperation(value = "下载数据文档模板")
@getmapping("/download-template/3")
public void downloadfile03(httpservletrequest request, httpservletresponse response) throws ioexception {
    resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
    // 设置响应头
    response.setcontenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream).tostring());
    response.setheader("content-disposition", "attachment; filename=" + encodefilename(request, resource.getfilename()));
  	//	这里是关键,如果设置 response.setcontentlength() 则下载的文件只能是 50 多兆
    response.setcontentlengthlong(resource.contentlength());
    fileutil.writetostream(resource.getfile(), response.getoutputstream());
}

方式四:通过responseentity<byte[]> 方式来下载

@apioperation(value = "下载数据文档模板")
@getmapping("/download-template/4")
public responseentity<byte[]> downloadfile04(httpservletrequest request, httpservletresponse response) throws ioexception {
    try {
        resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
        // 检查资源是否存在
        if (resource.exists() || resource.isreadable()) {
            return responseentity.ok()
                    .header(httpheaders.content_length, string.valueof(resource.contentlength()))
                    .header(httpheaders.content_disposition, "attachment; filename=" + encodefilename(request, resource.getfilename()))
                    .contenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream))
                    .body(fileutil.readbytes(resource.getfile()));
        } else {
            return responseentity.notfound().build();
        }
    } catch (exception e) {
        log.error("文件模板下载失败!", e);
        return responseentity.internalservererror().build();
    }
}

四种下载方式的对比

1、核心特性对比

方式内存占用适用场景流式支持资源管理代码复杂度
responseentity<byte[]>高(全量加载)小文件(<10mb)如配置文件、图片自动释放内存低(简单封装)
responseentity<resource>中(按需加载)动态资源(如jar内文件、数据库blob)✅(需手动关闭流)需显式关闭inputstream中(需处理流)
responseentity<streamingresponsebody>极低(分块传输)超大文件(视频、日志等)✅(自动分块)自动处理流生命周期高(需分块逻辑)
servlet原生下载低(手动控制)需要精细控制响应头/流的场景✅(手动实现)需手动关闭流高(冗余代码)

2、典型场景推荐

  • 快速小文件下载‌:优先使用responseentity<byte[]>,直接返回字节数组,无需流控制。
  • 动态资源或加密文件‌:选择responseentity<resource>,灵活处理输入流。
  • ‌**超大文件(gb级)**‌:必须用streamingresponsebody分块传输,避免oom。
  • 兼容旧系统或特殊需求‌:servlet原生下载(如需要自定义响应头逻辑)

完整的代码

import cn.hutool.core.io.fileutil;
import io.swagger.annotations.apioperation;
import lombok.extern.slf4j.slf4j;
import org.springframework.core.io.classpathresource;
import org.springframework.core.io.resource;
import org.springframework.http.httpheaders;
import org.springframework.http.mediatype;
import org.springframework.http.mediatypefactory;
import org.springframework.http.responseentity;
import org.springframework.stereotype.controller;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.servlet.mvc.method.annotation.streamingresponsebody;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import java.io.ioexception;
import java.nio.charset.standardcharsets;
/**
 * description
 *
 * @author lijin
 * @since 2025-08-12 14:05
 */
@slf4j
@controller
@requestmapping("/cycle-data/document01")
public class downloadcontroller {
    @apioperation(value = "下载数据文档模板")
    @getmapping("/download-template/1")
    public responseentity<resource> downloadfile01(httpservletrequest request) {
        try {
            resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
            // 检查资源是否存在
            if (resource.exists() || resource.isreadable()) {
                return responseentity.ok()
                        .header(httpheaders.content_length, string.valueof(resource.contentlength()))
                        .header(httpheaders.content_disposition, "attachment; filename=" + encodefilename(request, resource.getfilename()))
                        .contenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream))
                        .body(resource);
            } else {
                return responseentity.notfound().build();
            }
        } catch (exception e) {
            log.error("文件模板下载失败!", e);
            return responseentity.internalservererror().build();
        }
    }
    @apioperation(value = "下载数据文档模板")
    @getmapping("/download-template/2")
    public responseentity<streamingresponsebody> downloadfile02(httpservletrequest request) {
        try {
            resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
            streamingresponsebody body = outputstream -> {
                fileutil.writetostream(resource.getfile(), outputstream);
            };
            // 检查资源是否存在
            if (resource.exists() || resource.isreadable()) {
                return responseentity.ok()
                        .header(httpheaders.content_length, string.valueof(resource.contentlength()))
                        .header(httpheaders.content_disposition, "attachment; filename=" + encodefilename(request, resource.getfilename()))
                        .contenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream))
                        .body(body);
            } else {
                return responseentity.notfound().build();
            }
        } catch (exception e) {
            log.error("文件模板下载失败!", e);
            return responseentity.internalservererror().build();
        }
    }
    @apioperation(value = "下载数据文档模板")
    @getmapping("/download-template/3")
    public void downloadfile03(httpservletrequest request, httpservletresponse response) throws ioexception {
        resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
        // 设置响应头
        response.setcontenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream).tostring());
        response.setheader("content-disposition", "attachment; filename=" + encodefilename(request, resource.getfilename()));
        response.setcontentlengthlong(resource.contentlength());
        fileutil.writetostream(resource.getfile(), response.getoutputstream());
    }
    @apioperation(value = "下载数据文档模板")
    @getmapping("/download-template/4")
    public responseentity<byte[]> downloadfile04(httpservletrequest request, httpservletresponse response) throws ioexception {
        try {
            resource resource = new classpathresource("templates/ubuntu-20.04.6-desktop-amd64.iso");
            // 检查资源是否存在
            if (resource.exists() || resource.isreadable()) {
                return responseentity.ok()
                        .header(httpheaders.content_length, string.valueof(resource.contentlength()))
                        .header(httpheaders.content_disposition, "attachment; filename=" + encodefilename(request, resource.getfilename()))
                        .contenttype(mediatypefactory.getmediatype(resource).orelse(mediatype.application_octet_stream))
                        .body(fileutil.readbytes(resource.getfile()));
            } else {
                return responseentity.notfound().build();
            }
        } catch (exception e) {
            log.error("文件模板下载失败!", e);
            return responseentity.internalservererror().build();
        }
    }
    /**
     * 根据浏览器类型编码文件名
     * @param request 请求对象
     * @param filename 原始文件名
     * @return 编码后的文件名
     */
    private static string encodefilename(httpservletrequest request, string filename) {
        string useragent = request.getheader("user-agent");
        // 处理ie及edge浏览器
        if (useragent.contains("msie") || useragent.contains("trident") || useragent.contains("edge")) {
            return cn.hutool.core.net.urlencoder.createdefault().encode(filename, standardcharsets.utf_8);
        }
        // 其他浏览器使用iso-8859-1编码
        return new string(filename.getbytes(standardcharsets.utf_8), standardcharsets.iso_8859_1);
    }
}

到此这篇关于spring文件下载的四种方式及对比分析的文章就介绍到这了,更多相关spring文件下载内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com