从基础到实战详解SpringBoot获取资源文件全指南

 更新时间:2025年07月31日 09:36:08   作者:zk_xyb  
在 SpringBoot 开发中,我们经常需要访问各类资源文件,本文将系统讲解 SpringBoot 中资源文件的存放规则,获取方法及实战技巧,需要的可以了解下

在 SpringBoot 开发中,我们经常需要访问各类资源文件——配置文件、模板、静态资源等。不同于传统 Java 项目,SpringBoot 有其独特的资源管理机制,掌握正确的资源获取方式能避免很多"文件找不到"的坑。本文将系统讲解 SpringBoot 中资源文件的存放规则、获取方法及实战技巧。

一、SpringBoot 资源文件的存放位置

SpringBoot 对资源文件有约定俗成的存放规范,遵循这些规范能让资源访问更简单。默认的资源目录为 src/main/resources,其下常见子目录及用途如下:

目录路径用途说明典型文件示例
resources/根目录,可存放通用配置文件app.properties、logo.png
resources/config/配置文件目录,优先级高于根目录application-dev.yml
resources/static/静态资源目录(Web 项目)js/、css/、images/
resources/templates/模板文件目录(如 Thymeleaf、Freemarker)index.html、report.ftl
resources/i18n/国际化资源文件目录messages_zh_CN.properties

关键特性

  • 这些目录会被自动加入类路径(classpath),无需手动配置
  • 打包后(JAR 包),资源文件会被放在 JAR 内部的根目录或对应子目录中

二、获取资源文件的核心方法

SpringBoot 继承了 Java 的资源访问机制,并提供了更便捷的工具类。以下是常用的 4 种获取方式,适用于不同场景。

1. 基于 ClassLoader 的资源获取

原理:通过类加载器(ClassLoader)从类路径根目录查找资源,路径无需以 / 开头。

适用场景:资源文件放在 resources/ 根目录或子目录(如 config/static/)。

示例代码

import org.springframework.stereotype.Component;
import java.io.InputStream;

@Component
public class ResourceLoaderService {

    // 读取 resources/config/app.properties
    public void loadByClassLoader() {
        // 获取类加载器
        ClassLoader classLoader = getClass().getClassLoader();
        
        // 读取资源(路径从类路径根开始,无需加 /)
        try (InputStream is = classLoader.getResourceAsStream("config/app.properties")) {
            if (is != null) {
                // 读取文件内容(示例:转为字符串)
                byte[] buffer = new byte[is.available()];
                is.read(buffer);
                String content = new String(buffer);
                System.out.println("配置内容:" + content);
            } else {
                System.out.println("资源文件不存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. 基于 Class 的资源获取

原理:通过当前类的 Class 对象获取资源,路径可相对当前类的包路径,或通过 / 开头表示类路径根。

适用场景:资源与当前类在同一包下,或需要明确相对路径时。

示例代码

@Component
public class ResourceClassService {

    // 当前类位于 com.example.service 包
    // 资源文件位置:com/example/service/data.txt(与类同包)
    public void loadByClassRelative() {
        try (InputStream is = getClass().getResourceAsStream("data.txt")) {
            // 读取逻辑...
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 资源文件位置:resources/static/images/logo.png(类路径根下)
    public void loadByClassRoot() {
        // 路径以 / 开头,从类路径根开始查找
        try (InputStream is = getClass().getResourceAsStream("/static/images/logo.png")) {
            // 读取逻辑...
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意

  • 不带 / 的路径:相对当前类所在包(如 data.txt 对应 com/example/service/data.txt
  • / 的路径:相对类路径根(如 /static/logo.png 对应 resources/static/logo.png

3. 基于 Spring 的 ResourceLoader 工具类

原理:Spring 提供的 ResourceLoader 接口,统一资源访问抽象,支持多种资源类型(classpath、file、URL 等)。

适用场景:Spring 环境中推荐使用,支持更丰富的路径表达式(如 classpath*: 匹配多个资源)。

示例代码

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.InputStream;

@Component
public class SpringResourceService {

    @Resource
    private ResourceLoader resourceLoader;

    // 读取单个资源
    public void loadSingleResource() {
        try {
            // 加载类路径下的 templates/report.xlsx
            Resource resource = resourceLoader.getResource("classpath:templates/report.xlsx");
            if (resource.exists()) {
                try (InputStream is = resource.getInputStream()) {
                    // 读取逻辑...
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 读取多个资源(classpath*: 匹配所有符合条件的资源)
    public void loadMultipleResources() {
        try {
            // 加载所有 JAR 包中 META-INF/spring.factories 文件
            Resource[] resources = resourceLoader.getResources("classpath*:META-INF/spring.factories");
            for (Resource res : resources) {
                System.out.println("找到资源:" + res.getFilename());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

特殊路径表达式

  • classpath:xxx:从类路径查找单个资源
  • classpath*:xxx:从类路径查找所有匹配的资源(包括 JAR 包内)
  • file:xxx:从本地文件系统查找(绝对路径或相对当前项目根目录)

4. 基于 @Value 注解的配置文件读取

原理:通过 Spring 的 @Value 注解直接注入配置文件中的属性值,无需手动读取文件。

适用场景:仅需获取配置文件(如 application.ymlcustom.properties)中的特定属性。

示例代码

1.资源文件 resources/config/custom.properties

app.name=SpringBoot资源示例
app.version=1.0.0
app.enabled=true

2.注入配置的代码:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class ConfigPropertiesService {

    // 注入配置值(默认从 application.properties/yml 读取,可指定其他文件)
    @Value("${app.name:默认名称}") // 冒号后为默认值
    private String appName;

    @Value("${app.version}")
    private String appVersion;

    @Value("${app.enabled}")
    private boolean enabled;

    // 如需读取其他配置文件,需在启动类添加 @PropertySource 注解
    // @PropertySource("classpath:config/custom.properties")
    public void printConfig() {
        System.out.println("应用名称:" + appName);
        System.out.println("版本号:" + appVersion);
        System.out.println("是否启用:" + enabled);
    }
}

注意

  • 需在启动类添加 @PropertySource("classpath:config/custom.properties") 才能识别非默认配置文件
  • 支持 SpEL 表达式,如 @Value("#{T(java.lang.Integer).parseInt('${app.port:8080}')}")

三、常见问题与解决方案

1. 资源文件打包后找不到

原因

  • 资源文件未放在 src/main/resources 目录,导致未被打包进 JAR
  • 使用绝对路径(如 D:/file.txt),但部署环境中路径不存在

解决

  • 确保资源放在标准目录下,通过 classpath: 路径访问
  • 打包后通过 Resource.exists() 检查资源是否存在
// 检查资源是否存在
Resource resource = resourceLoader.getResource("classpath:config/app.properties");
if (!resource.exists()) {
    throw new RuntimeException("资源文件不存在:" + resource.getDescription());
}

2. 读取 JAR 包内资源时无法通过 File 访问

原因:JAR 包内的资源是压缩文件中的条目,并非本地文件系统的真实文件,无法通过 new File(...) 访问。

解决

  • 必须通过输入流(InputStream)读取,而非 File 对象
  • 如需临时文件,可将资源复制到系统临时目录:
import org.springframework.core.io.Resource;
import java.io.File;
import java.nio.file.Files;

public void copyResourceToTempFile(Resource resource) throws Exception {
    File tempFile = File.createTempFile("temp", ".txt");
    Files.copy(resource.getInputStream(), tempFile.toPath());
    System.out.println("临时文件路径:" + tempFile.getAbsolutePath());
}

3. 多模块项目中资源文件如何共享

场景:在 Maven 多模块项目中,A 模块需要访问 B 模块的资源文件。

解决

  • 将共享资源放在公共模块(如 common 模块)的 src/main/resources
  • 通过 classpath*: 路径匹配所有模块的资源:
// 读取所有模块中 META-INF/shared.properties 文件
Resource[] resources = resourceLoader.getResources("classpath*:META-INF/shared.properties");

四、最佳实践总结

优先使用 Spring 提供的工具ResourceLoader@Value 是 Spring 环境的最佳选择,适配各种部署场景(JAR、WAR、容器化)。

避免硬编码路径:通过配置文件(如 application.yml)定义资源路径,方便后期修改:

resource:
  template-path: classpath:templates/report.xlsx

代码中注入路径后再加载:

@Value("${resource.template-path}")
private String templatePath;

public void loadTemplate() {
    Resource resource = resourceLoader.getResource(templatePath);
}

区分开发与生产环境:开发时可通过 file: 路径访问本地文件(方便调试),生产环境切换为 classpath: 路径:

// 开发环境:file:src/main/resources/test.txt
// 生产环境:classpath:test.txt
@Value("${app.resource-path:classpath:test.txt}")
private String resourcePath;

处理大文件:对于超过 100MB 的资源文件,建议通过 Resource.getInputStream() 流式读取,避免一次性加载到内存。

掌握这些方法后,无论资源文件是在本地开发目录、JAR 包内,还是分布式环境中,都能轻松获取。SpringBoot 的资源管理机制看似复杂,实则遵循"约定优于配置"的原则,理解其底层逻辑后,就能举一反三应对各种场景。

相关文章

  • 浅谈java多线程wait,notify

    浅谈java多线程wait,notify

    这篇文章主要介绍了java多线程wait,notify,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面小编和大家一起来学习一下吧
    2019-05-05
  • java多线程编程同步器Future和FutureTask解析及代码示例

    java多线程编程同步器Future和FutureTask解析及代码示例

    这篇文章主要介绍了java多线程编程同步器Future和FutureTask解析及代码示例,对二者进行了详细介绍,分析了future的源码,最后展示了相关实例代码,具有一定参考价值 ,需要的朋友可以了解下。
    2017-11-11
  • SpringBoot中集成Swagger2及简单实用

    SpringBoot中集成Swagger2及简单实用

    使用Swagger你只需要按照它的规范去定义接口及接口相关的信息,再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线接口调试页面等等,这篇文章主要介绍了SpringBoot中集成Swagger2,需要的朋友可以参考下
    2023-06-06
  • Springmvc实现文件下载2种实现方法

    Springmvc实现文件下载2种实现方法

    这篇文章主要介绍了Springmvc实现文件下载2种实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • java 单例模式和工厂模式实例详解

    java 单例模式和工厂模式实例详解

    这篇文章主要介绍了Java设计模式编程中的单例模式和简单工厂模式以及实例,使用设计模式编写代码有利于团队协作时程序的维护,需要的朋友可以参考下
    2017-04-04
  • Java使用BIO和NIO进行文件操作对比代码示例

    Java使用BIO和NIO进行文件操作对比代码示例

    这篇文章主要介绍了Java使用BIO和NIO进行文件操作对比代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • java方法替换word文档中需要替换的部分操作步骤

    java方法替换word文档中需要替换的部分操作步骤

    这篇文章主要介绍了java方法替换word文档中需要替换的部分操作的相关资料,需要的朋友可以参考下,包括引入依赖、创建业务方法、测试以及扩展功能,需要的朋友们可以参考下
    2024-12-12
  • java用户管理注册功能 含前后台代码

    java用户管理注册功能 含前后台代码

    这篇文章主要介绍了java用户管理注册功能,含前端和后台代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 解决SpringMVC、tomcat、Intellij idea、ajax中文乱码问题

    解决SpringMVC、tomcat、Intellij idea、ajax中文乱码问题

    这篇文章主要介绍了解决SpringMVC、tomcat、Intellij idea、ajax中文乱码问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 解决java中mybatis报错:org.apache.ibatis.binding.BindingException:Invalid bound statement(not found):xx问题

    解决java中mybatis报错:org.apache.ibatis.binding.BindingException:

    这篇文章主要介绍了解决java中mybatis报错:org.apache.ibatis.binding.BindingException:Invalid bound statement(not found):xx问题,具有很好的参考价值,希望对大家有所帮助
    2024-03-03

最新评论