Excel模板下载(Resources目录下)

🍓 简介:java系列技术分享(👉持续更新中...🔥)

🍓 初衷:一起学习、一起进步、坚持不懈

🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏

🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

🍓 更多文章请点击

文章目录

本文提供多种获取resources目录下文件的方式

一、方式一(getClassLoader)

使用getResourceAsStream方法获取流,在SpringBoot中所有文件都在jar包中,没有一个实际的路径,因此可以使用以下方式。

java 复制代码
    /**
     * 直接使用getResourceAsStream方法获取流
     *
     * @param fileName
     * @throws IOException
     */
    public void function4(String fileName) throws IOException {
        InputStream in = this.getClass().getClassLoader().getResourceAsStream(fileName);
    }

二、方式二(getClass())

使用getResourceAsStream方法获取流,不使用getClassLoader可以使用getResourceAsStream("/测试.txt")直接从resources根路径下获取,SpringBoot中所有文件都在jar包中,没有一个实际的路径,因此可以使用以下方式。

java 复制代码
    /**
     * 直接使用getResourceAsStream方法获取流
     *
     * @param fileName
     * @throws IOException
     */
    public void function5(String fileName) throws IOException {
        InputStream in = this.getClass().getResourceAsStream("/" + fileName);
    }

三、方式三(ClassPathResource)(Spring Boot 项目-推荐)

通过ClassPathResource类获取文件流,SpringBoot中所有文件都在jar包中,没有一个实际的路径,因此可以使用以下方式。

java 复制代码
    /**
     * 通过ClassPathResource类获取,建议SpringBoot中使用
     *
     * @param fileName
     * @throws IOException
     */
    public void function6(String fileName) throws IOException {
        ClassPathResource classPathResource = new ClassPathResource(fileName);
        InputStream inputStream = classPathResource.getInputStream();
        getFileContent(inputStream);
    }

四、三种方式区别对别

假设 fileName = "excel/模板.xlsx"

java 复制代码
// 方式1:ClassLoader - 始终从 classpath 根路径
InputStream in = this.getClass().getClassLoader().getResourceAsStream(fileName);
// 实际查找路径:classpath:/excel/模板.xlsx

// 方式2:Class - 需要手动加 / 才能到根路径
InputStream in = this.getClass().getResourceAsStream("/" + fileName);
// 实际查找路径:classpath:/excel/模板.xlsx

// 方式3:ClassPathResource - 默认从根路径,可加 / 或不加
ClassPathResource resource = new ClassPathResource(fileName);
InputStream inputStream = resource.getInputStream();
// fileName 可以是 "excel/模板.xlsx" 或 "/excel/模板.xlsx",效果相同

4.1 路径处理详细对比

方式 路径示例 实际查找路径 支持 / 开头
ClassLoader "excel/模板.xlsx" classpath:/excel/模板.xlsx
ClassLoader "/excel/模板.xlsx" classpath:/excel/模板.xlsx ⚠️
Class "excel/模板.xlsx" classpath:/包路径/excel/模板.xlsx
Class "/excel/模板.xlsx" classpath:/excel/模板.xlsx
ClassPathResource "excel/模板.xlsx" classpath:/excel/模板.xlsx
ClassPathResource "/excel/模板.xlsx" classpath:/excel/模板.xlsx

4.2 核心优势对比

维度 ClassPathResource Class.getResourceAsStream
资源存在性检查 ✅ 提供 exists() 方法 ❌ 无法提前检查,返回 null 才知道
文件信息获取 ✅ 可获取 URL、URI、文件名等 ❌ 只有 InputStream
Spring 生态集成 ✅ 完美集成,支持注入 ⚠️ 需要手动处理
异常处理 ✅ 抛出明确的 IOException ❌ 返回 null,容易 NPE
单元测试友好 ✅ 易于 Mock ⚠️ 需要 PowerMock
路径灵活性 ✅ 支持 classpath:/ 前缀 ⚠️ 需要加 / 或不加

4.3 总结建议

项目类型 推荐方案 理由
Spring Boot 项目 ClassPathResource 功能丰富、易测试、支持注入
传统 Spring 项目 ClassPathResource 与 Spring 生态完美集成
非 Spring 项目 Class.getResourceAsStream 轻量、无需依赖
需要文件信息 ClassPathResource 可获取文件名、大小等
需要配置化路径 ClassPathResource + @Value 支持外部配置

五、Excel模板下载

5.1 Controller

java 复制代码
    /**
     * 模板导出
     *
     * @param response response
     */
    @GetMapping("/exportTemplate")
    public void exportTemplate(HttpServletResponse response){
        manageService.exportTemplate(response);
    }

5.2 Service

java 复制代码
    /**
     * 模板导出
     *
     * @param response response
     */
    void exportTemplate(HttpServletResponse response);

5.3 Impl

this.getClass().getClassLoader().getResourceAsStream方式

java 复制代码
@Override
public void exportTemplate(HttpServletResponse response) {
     try {
         String finalFileName = "模板.xlsx";
         InputStream fileStream;
         byte[] bytes = new byte[300000];

         fileStream = this.getClass().getResourceAsStream("/excel/模板.xlsx");
         fileStream.read(bytes);

         OutputStream outputStream = null;
         try {
             outputStream = response.getOutputStream();
             // 设值返回文件属性,浏览器会根据属性调用下载文件方法
             response.addHeader("Content-Disposition",
                     "attachment;filename=" + URLEncoder.encode(finalFileName, "utf-8"));
             // 设值文件大小属性,浏览器用于判断文件是否写完
             response.addHeader("Content-Length", "" + bytes.length);
             // 前端获取文件名,需要解码
             response.addHeader("downLoadName", URLEncoder.encode(finalFileName, "utf-8"));
             // 定义输出流
             outputStream = new BufferedOutputStream(response.getOutputStream());
             // 定义输出类型为二进制流输出
             response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
             response.setCharacterEncoding("UTF-8");
             outputStream.write(bytes);
             outputStream.flush();
         } catch (Exception e) {
             throw BusinessException.buildBusinessExceptionAlert("程序异常");
         } finally {
             outputStream.close();
         }
     } catch (BusinessException error) {
         throw error;
     } catch (Exception e) {
         log.error("模板导出异常", e);
         throw new BusinessException("-1", "模板导出异常,请稍后重试");
     }
 }

ClassPathResource方式

java 复制代码
@Override
public void exportTemplate(HttpServletResponse response) {
    String fileName = "模板.xlsx";
    String resourcePath = "/excel/模板.xlsx";
    
    // 使用 ClassPathResource 统一处理
    ClassPathResource resource = new ClassPathResource(resourcePath);
    
    try {
        // 1. 检查资源
        if (!resource.exists()) {
            throw BusinessException.buildBusinessExceptionAlert("模板文件不存在");
        }
        
        // 2. 设置响应头(包括准确的 Content-Length)
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", 
            "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
        response.setHeader("downLoadName", URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
        response.setContentLengthLong(resource.contentLength());  // ✅ 准确设置大小
        
        // 3. 流拷贝
        try (InputStream inputStream = resource.getInputStream();
             OutputStream outputStream = response.getOutputStream()) {
            FileCopyUtils.copy(inputStream, outputStream);
            outputStream.flush();
        }
        
    } catch (BusinessException e) {
        throw e;
    } catch (Exception e) {
        log.error("模板导出异常", e);
        throw new BusinessException("-1", "模板导出异常,请稍后重试");
    }
}

相关推荐
石榴树下的七彩鱼1 小时前
图片修复 API 接入实战:网站如何自动去除图片水印(Python / PHP / C# 示例)
图像处理·后端·python·c#·php·api·图片去水印
我叫黑大帅1 小时前
为什么TCP是三次握手?
后端·网络协议·面试
我叫黑大帅1 小时前
如何排查 MySQL 慢查询
后端·sql·面试
techdashen1 小时前
Rust项目公开征测:Cargo 构建目录新布局方案
开发语言·后端·rust
一 乐1 小时前
电影院|基于springboot + vue电影院购票管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·电影院购票管理管理系统
恼书:-(空寄1 小时前
JVM GC 日志分析 + 常见 GC 场景 + 实战参数调优
java·jvm
消失的旧时光-19431 小时前
Spring Boot 实战(五):接口工程化升级(统一返回 + 异常处理 + 错误码体系 + 异常流转机制)
java·spring boot·后端·解耦
Rust研习社2 小时前
Rust 智能指针 Cell 与 RefCell 的内部可变性
开发语言·后端·rust
夕颜1112 小时前
Skill 机器人 vs Hermes Agent:两种「AI 越用越聪明」的路径
后端
杨凯凡3 小时前
【012】图与最短路径:了解即可
java·数据结构