使用 ResourceLoader 统一管理你的本地资源

linbojue
• 阅读 2

前言 在项目开发中,我们经常需要读取各种本地资源文件:配置文件、模板文件、静态资源、数据文件等。 Spring 框架提供了一个强大而优雅的解决方案——ResourceLoader 接口。本文将使用 Spring ResourceLoader 统一管理本地资源,让你的代码更加规范、灵活且易于维护。 一、ResourceLoader 的优势 Spring 的 ResourceLoader 提供了一个统一的资源访问抽象: java 体验AI代码助手 代码解读复制代码public interface ResourceLoader { Resource getResource(String location); }

它的优势在于: 统一接口:无论资源来自文件系统、classpath 还是 URL,都用相同方式访问 位置透明:支持多种位置前缀,如 classpath:、file:、http: 等 Spring 生态集成:与 Spring 容器完美集成,自动注入 灵活性:支持模式匹配、占位符解析等高级特性 二、核心概念与接口 2.1 Resource 接口 Resource 是 Spring 对底层资源的抽象,它继承自 InputStreamSource 接口: java 体验AI代码助手 代码解读复制代码public interface Resource extends InputStreamSource { boolean exists(); boolean isReadable(); boolean isOpen(); boolean isFile(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription(); }

常见的 Resource 实现类:

实现类用途FileSystemResource文件系统资源ClassPathResourceclasspath 资源UrlResourceURL 资源(支持 http、ftp 等)ServletContextResourceWeb 应用上下文资源 PathMatchingResourcePatternResolver 是资源解析器,用于批量匹配资源路径,它实现了 ResourcePatternResolver 接口。 2.2 ResourceLoader 接口 ResourceLoader 是资源加载的核心接口: java 体验AI代码助手 代码解读复制代码public interface ResourceLoader { Resource getResource(String location); }

2.3 ResourcePatternResolver 接口 ResourcePatternResolver 是 ResourceLoader 的扩展,支持资源模式匹配: java 体验AI代码助手 代码解读复制代码public interface ResourcePatternResolver extends ResourceLoader { String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

Resource[] getResources(String locationPattern) throws IOException;

}

关键特性是 classpath: 前缀,它可以匹配 classpath 下所有同名资源: java 体验AI代码助手 代码解读复制代码// 匹配所有 classpath 下的 *.xml 文件 Resource[] resources = resolver.getResources("classpath:*.xml");

三、常用资源位置前缀 Spring 支持多种资源位置前缀,每种前缀对应不同的资源来源: 3.1 classpath: 前缀 从 classpath 读取资源,这是最常用的方式: java 体验AI代码助手 代码解读复制代码Resource resource = resourceLoader.getResource("classpath:config/app.properties"); // 或者简写,ResourceLoader 会自动识别 Resource resource = resourceLoader.getResource("config/app.properties");

3.2 file: 前缀 明确指定从文件系统读取: java 体验AI代码助手 代码解读复制代码Resource resource = resourceLoader.getResource("file:/data/config/app.properties");

3.3 http: / https: 前缀 从网络读取资源: java 体验AI代码助手 代码解读复制代码Resource resource = resourceLoader.getResource("https://example.com/config.json");

3.4 无前缀 Spring 会根据资源路径的特征自动判断来源: java 体验AI代码助手 代码解读复制代码// 以 / 开头,视为文件系统路径 Resource resource = resourceLoader.getResource("/etc/app/config.properties");

// 其他情况,优先从 classpath 查找 Resource resource = resourceLoader.getResource("config/app.properties");

四、最佳实践 4.1 基础用法 在 Spring Boot 应用中,我们可以直接注入 ResourceLoader: java 体验AI代码助手 代码解读复制代码@Service public class ConfigLoader {

private final ResourceLoader resourceLoader;

public ConfigLoader(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
}

public Properties loadProperties() throws IOException {
    Resource resource = resourceLoader.getResource("classpath:application.properties");
    Properties props = new Properties();
    props.load(resource.getInputStream());
    return props;
}

}

4.2 资源目录结构规划 建议按照以下结构组织资源文件: css 体验AI代码助手 代码解读复制代码src/main/resources/ ├── config/ │ ├── app.properties │ └── database.properties ├── templates/ │ ├── email/ │ │ └── welcome.html │ └── report/ │ └── monthly.xlsx └── data/ ├── initial-data.json └── lookup-tables.csv

4.3 批量读取资源文件 使用 ResourcePatternResolver 可以批量读取匹配模式的资源: java 体验AI代码助手 代码解读复制代码@Service public class TemplateLoader {

private final ResourcePatternResolver resourcePatternResolver;

public TemplateLoader(ResourcePatternResolver resourcePatternResolver) {
    this.resourcePatternResolver = resourcePatternResolver;
}

public Map<String, String> loadAllTemplates() throws IOException {
    Map<String, String> templates = new HashMap<>();

    // 读取所有 HTML 模板
    Resource[] resources = resourcePatternResolver
        .getResources("classpath*:templates/**/*.html");

    for (Resource resource : resources) {
        String path = resource.getPath();
        String name = path.substring(path.lastIndexOf("templates/"));
        try (InputStream is = resource.getInputStream()) {
            templates.put(name, new String(is.readAllBytes(), StandardCharsets.UTF_8));
        }
    }
    return templates;
}

}

4.4 统一路径管理 推荐使用配置属性 + 常量类的方式:

  1. 定义资源路径常量类 java 体验AI代码助手 代码解读复制代码public final class ResourcePaths {

    private ResourcePaths() {}

    // 配置文件 public static final String CONFIG_DIR = "classpath:config/"; public static final String APP_PROPERTIES = CONFIG_DIR + "app.properties"; public static final String DATABASE_PROPERTIES = CONFIG_DIR + "database.properties";

    // 模板文件 public static final String TEMPLATES_DIR = "classpath:templates/"; public static final String EMAIL_WELCOME = TEMPLATES_DIR + "email/welcome.html";

    // 数据文件 public static final String DATA_DIR = "classpath:data/"; public static final String INITIAL_DATA = DATA_DIR + "initial-data.json"; }

  2. 使用配置属性(推荐) 在 application.yml 中集中管理: yaml 体验AI代码助手 代码解读复制代码app: resource: config-dir: classpath:config/ templates-dir: classpath:templates/ data-dir: classpath:data/

对应的配置属性类: java 体验AI代码助手 代码解读复制代码@ConfigurationProperties(prefix = "app.resource") public record ResourceProperties( String configDir, String templatesDir, String dataDir ) { public String getConfigPath(String fileName) { return configDir + fileName; } }

  1. 统一资源服务 封装资源访问逻辑,统一处理路径和异常 java 体验AI代码助手 代码解读复制代码@Service public class ResourceService {

    private final ResourceLoader resourceLoader; private final ResourceProperties properties;

    public ResourceService(ResourceLoader resourceLoader, ResourceProperties properties) {

     this.resourceLoader = resourceLoader;
     this.properties = properties;

    }

    /**

    • 读取配置文件(Properties 格式)

    • / public Properties loadProperties(String fileName) throws IOException { Resource resource = resourceLoader.getResource(properties.getConfigPath(fileName)); Properties props = new Properties(); try (InputStream is = resource.getInputStream()) {

        props.load(is);

      } return props; }

      /**

    • 读取模板文件内容

    • / public String readTemplate(String relativePath) throws IOException { Resource resource = resourceLoader.getResource(properties.templatesDir() + relativePath); try (InputStream is = resource.getInputStream()) {

        return new String(is.readAllBytes(), StandardCharsets.UTF_8);

      } }

      /**

    • 批量加载模板(支持 Ant 风格模式)

    • / public Map<String, String> loadTemplates(String pattern) throws IOException { Map<String, String> templates = new HashMap<>(); Resource[] resources = ((ResourcePatternResolver) resourceLoader)

        .getResources(properties.templatesDir() + pattern);

      for (Resource resource : resources) {

        String path = resource.getFilename();
        try (InputStream is = resource.getInputStream()) {
            templates.put(path, new String(is.readAllBytes(), StandardCharsets.UTF_8));
        }

      } return templates; }

      /**

    • 检查资源是否存在

    • / public boolean exists(String path) { return resourceLoader.getResource(path).exists(); } }

使用示例: java 体验AI代码助手 代码解读复制代码@Service public class EmailService {

private final ResourceService resourceService;

public EmailService(ResourceService resourceService) {
    this.resourceService = resourceService;
}

public String getWelcomeTemplate() {
    try {
        return resourceService.readTemplate("email/welcome.html");
    } catch (IOException e) {
        throw new RuntimeException("Failed to load welcome template", e);
    }
}

}

4.5 轻量级工具类 也可以封装一个工具类 java 体验AI代码助手 代码解读复制代码public final class ResourceUtils {

private static ResourcePatternResolver resolver;

// Spring 注入
public static void setResourcePatternResolver(ResourcePatternResolver resolver) {
    ResourceUtils.resolver = resolver;
}

/**
 * 读取资源为字符串
 */
public static String readAsString(String path) throws IOException {
    Resource resource = resolver.getResource(path);
    try (InputStream is = resource.getInputStream()) {
        return new String(is.readAllBytes(), StandardCharsets.UTF_8);
    }
}

/**
 * 批量获取匹配的资源路径
 */
public static List<String> listResources(String pattern) throws IOException {
    Resource[] resources = resolver.getResources(pattern);
    return Arrays.stream(resources)
            .map(r -> {
                try {
                    return r.getURL().getPath();
                } catch (IOException e) {
                    return pattern;
                }
            })
            .collect(Collectors.toList());
}

}

在配置类中初始化: java 体验AI代码助手 代码解读复制代码@Configuration public class ResourceConfig {

@Bean
public ResourceUtils resourceUtils(ResourcePatternResolver resolver) {
    ResourceUtils.setResourcePatternResolver(resolver);
    return new ResourceUtils();
}

}

使用示例: java 体验AI代码助手 代码解读复制代码String template = ResourceUtils.readAsString(ResourcePaths.EMAIL_WELCOME); List configs = ResourceUtils.listResources("classpath:config/*.properties");

五、总结 Spring ResourceLoader 提供了统一的资源访问接口,支持 classpath、file、http 等多种前缀,配合 ResourcePatternResolver 可实现批量资源加载,让本地资源管理更加简洁规范。

https://infogram.com/9862pdf-1h0n25opley1l4p https://infogram.com/9862pdf-1hnp27eqy8e3y4g https://infogram.com/9862pdf-1h0r6rzw5nz3w4e https://infogram.com/9862pdf-1h0n25opleoxz4p https://infogram.com/9862pdf-1hnq41opzvopk23 https://infogram.com/9862pdf-1h984wv1dev7d2p https://infogram.com/9862pdf-1h9j6q75k171v4g https://infogram.com/9862pdf-1h984wv1dej0z2p https://infogram.com/9862pdf-1h7v4pd08z3r84k https://infogram.com/9862pdf-1h984wv1dejrd2p

点赞
收藏
评论区
推荐文章
Stella981 Stella981
4年前
Maven第四篇【私有仓库、上传jar包、引用私服jar包、上传本地项目到私服】
搭建私有服务器前面已经说过了,我们使用Maven的使用,如果需要导入相对应的jar包,Maven首先会在我们的本地仓库中寻找—私有仓库—中心仓库…然而,我们的本地仓库常常没有想要的jar包的,而经常去中心仓库下载这就非常浪费时间和资源了…因此我们一般都有一个私有仓库…另外有些公司都不提供外网给项目组人员,因此就不能使用mave
Stella981 Stella981
4年前
Android 在Java代码中设置style属性
在andriod开发中,很大一部分都要与资源打交道,比如说:图片,布局文件,字符串,样式等等。这给我们想要开发一些公共的组件带来很大的困难,因为公共的组件可能更愿意以jar包的形式出现。但是java的jar包中只允许出现java代码而不能出现资源。当我们想要以jar包的形式提供我们自己开发的公共组件时,我们就需要把以代码的形式创建资源。下面提供一个使
Stella981 Stella981
4年前
Spring Boot教程(二十)开发Web应用(1)
静态资源访问在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源。默认配置SpringBoot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则:/static/public/resources/METAINF/resources举例:
Wesley13 Wesley13
4年前
Java 读取Properties文件时应注意的路径问题
1\.使用Class的getResourceAsStream()方法读取Properties文件(资源文件)的路径问题:      InputStreaminthis.getClass().getResourceAsStream("资源Name");    注意:    (1)这种方式要求Properties资源文件必须与当
Stella981 Stella981
4年前
Node.js 读本地文件和发起 POST 网络请求
最近需要使用Nodejs读取本地文件中的数据构造请求去批量请求CGI获取数据,这样就不用手工搬砖了。因为需要携带Cookie,故使用POST方法。代码//读取本地文件varfsrequire("fs");varreadlinerequire('readline');
Wesley13 Wesley13
4年前
08、开源游戏
资源加载器 resourceloader.js初始化资源加载器用于读取图片和音乐,在前面的代码(main.js)中,我们初始化了它,下面我们详细说下,因为它在以后中会经常用到,游戏中所有的资源都由它来读取。$(window).load(function() {resourceloader.init();
Easter79 Easter79
4年前
ThreadLocal实现线程安全
Spring通过各种模板类降低了开发者使用各种数据持久技术的难度。这些模板类都是线程安全的,也就是说,多个DAO可以复用同一个模板实例而不会发生冲突。我们使用模板类访问底层数据,根据持久化技术的不同,模板类需要绑定数据连接或会话的资源。但这些资源本身是非线程安全的,也就是说它们不能在同一时刻被多个线程共享。虽然模板类通过资源池获取数据连接或会话,但资源池本身
Wesley13 Wesley13
4年前
R语言 以打开文件的方式设置数据读取路径
直接运行下代码前两行,然后在本地选择你要读取的数据文件,然后运行第三行,即可成功读取数据。csvpath<file.choose()!(https://oscimg.oschina.net/oscnet/c180866ce0f95eee8b0c0520168dd71aa69.png)本文分享自微信公众号数据驱动实践(Data
轻轻松松实现本地和云主机之间的文件上传下载
云主机开通后在进行应用部署时面临的第一个问题是如何将应用软件安装包、应用数据上传至云主机。利用几个很简单的工具就可以将本地文件上传至云主机。先说Windows云主机。Windows远程桌面支持远程驱动器映射,通过配置将本地硬盘映射为云主机的一个磁盘,就可以将本地磁盘的文件拷到云主机上。配置方法为运行远程桌面客户端,点击本地资源,找到本地设备和资源部分,点击详
程序员小五 程序员小五
2年前
如何自定义本地通知提示音
如果使用了SDK的本地通知,只想自定义本地通知的提示音,可以参考如下:自定义声音文件,命名为“smsreceived”,格式为“caf”(这里是SDK代码根据这个命名来判断设置本地通知提示音的,所以一定要一致)找到工程中添加的sdk的资源文件RongClo