从零开始 Spring Boot 28:资源

news2025/1/19 7:49:55

从零开始 Spring Boot 28:资源

spring boot

图源:简书 (jianshu.com)

Resource 接口

Spring中的资源被抽象为一个Resource接口:

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;

    ReadableByteChannel readableChannel() throws IOException;

    long contentLength() throws IOException;

    long lastModified() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    String getFilename();

    String getDescription();
}

Resource 接口中最重要的一些方法是。

  • getInputStream(): 定位并打开资源,返回一个用于读取资源的 InputStream。我们期望每次调用都能返回一个新的 InputStream。关闭该流是调用者的责任。
  • exists(): 返回一个 boolean 值,表示该资源是否以物理形式实际存在。
  • isOpen(): 返回一个 boolean,表示该资源是否代表一个具有开放流的句柄。如果为 trueInputStream 不能被多次读取,必须只读一次,然后关闭以避免资源泄漏。对于所有通常的资源实现,除了 InputStreamResource 之外,返回 false
  • getDescription(): 返回该资源的描述,用于处理该资源时的错误输出。这通常是全路径的文件名或资源的实际URL。

内置的Resource实现

Spring内置了一些Resource接口的实现类:

  • UrlResource
  • ClassPathResource
  • FileSystemResource
  • PathResource
  • ServletContextResource
  • InputStreamResource
  • ByteArrayResource

这里介绍几个常见的Resource实现类。

ClassPathResource

ClassPathResource是最常见的,通过它我们可以访问ClassPath中的文件。

举例说明,假如在Spring的静态资源目录resources下有一个文件override.properties

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb

可以通过下面的示例代码将其内容打印到控制台:

package com.example.resource.controller;
// ...
@RestController
@RequestMapping("/hello")
public class HelloController {
    @GetMapping("")
    public String hello() throws IOException {
        Resource resource = new ClassPathResource("override.properties");
        printContent(resource);
        return Result.success().toString();
    }

    private void printContent(Resource resource) throws IOException {
        File file;
        try {
            file = resource.getFile();
        } catch (FileNotFoundException e) {
            String content = resource.getContentAsString(StandardCharsets.UTF_8);
            System.out.println(content);
            return;
        }
        printContent(file);
    }

    private void printContent(File file) throws IOException {
        FileReader fr;
        fr = new FileReader(file);
        BufferedReader br = new BufferedReader(fr);
        String line;
        do {
            line = br.readLine();
            if (line == null) {
                break;
            }
            System.out.println(line);
        }
        while (true);
        br.close();
    }
}

这其中下面这行代码,明确创建了一个到resources/override.properties文件的资源:

Resource resource = new ClassPathResource("override.properties");

如果Spring项目是通过IDE运行的,那么resources这个静态资源目录会被加入ClassPath,因此自然可以通过ClassPathResource正确访问到,如果项目是打包成Jar包运行,该目录同样会被打包的Jar包中的/BOOT-INF/classes目录:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CuYSJIK3-1684032458114)(D:\image\typora\image-20230513172429162.png)]

该目录同样会被加入ClassPath中,所以同样可以获取到正确的文件。

正是因为这样的特性,所以在开发中通常都会用ClassPath的方式引用静态资源,而非文件路径。因为后者可能导致部署的目标服务器上缺少相应的资源而出错。

FileSystemResource

FileSystemResource是通过文件系统来访问资源,具体来说就是文件的相对路径和绝对路径。

同样是上面的示例,只需要稍微修改:

    // ...
	@GetMapping("")
    public String hello() throws IOException {
        Resource resource = new FileSystemResource("src/main/resources/override.properties");
        printContent(resource);
        return Result.success().toString();
    }
	// ...

当然也可以使用绝对路径:

Resource resource = new FileSystemResource("D:/workspace/learn_spring_boot/ch28/resource/src/main/resources/override.properties");

UrlResource

通过UrlResource可以访问用URL定义的资源,当然最常见的是网络资源:

Resource resource = new UrlResource("https://blog.icexmoon.cn/");

要说明的是,通过UrlResource创建的Resource,是无法通过调用Resource.getFile()方法获取文件的,会产生FileNotFoundException异常。因此只能是以Resource.getInputStream()方法获取输入流,然后再打印内容。不过Resource接口其实已经提供了一个getContentAsString()方法:

public interface Resource extends InputStreamSource {
    // ...
	default String getContentAsString(Charset charset) throws IOException {
        return FileCopyUtils.copyToString(new InputStreamReader(this.getInputStream(), charset));
    }
    // ...
}

URL实际上也可以指定本地文件系统:

Resource resource = new UrlResource("file://D:/workspace/learn_spring_boot/ch28/resource/src/main/resources/override.properties");

其它的Resource实现可以阅读核心技术 (springdoc.cn)。

ResourceLoader 接口

可以通过接口ResourceLoader来获取Resource

public interface ResourceLoader {

    Resource getResource(String location);

    ClassLoader getClassLoader();
}

所有的application context都实现了这个接口,可以当做ResourceLoader来使用:

@RestController
@RequestMapping("/hello")
public class HelloController {
    @Autowired
    private ApplicationContext ctx;
    @GetMapping("")
    public String hello() throws IOException {
        Resource resource = ctx.getResource("classpath:override.properties");
        printContent(resource);
        return Result.success().toString();
    }
}

实际上在这个示例中,直接注入ResourceLoader更为合适:

@RestController
@RequestMapping("/hello")
public class HelloController {
    @Autowired
    private ResourceLoader resourceLoader;
    @GetMapping("")
    public String hello() throws IOException {
        Resource resource = resourceLoader.getResource("classpath:override.properties");
        printContent(resource);
        return Result.success().toString();
    }
    // ...
}

作为参数传入getResource方法的classpath:override.properties这样的被称作资源字符串

前缀示例说明
classpath:classpath:com/myapp/config.xml从classpath加载。
file:file:///data/config.xml作为 URL 从文件系统加载。另请参见FileSystemResource 注意事项.
https:https://myserver/logo.pngURL 形式加载。
(none)/data/config.xml取决于底层的 `ApplicationContext’。

如果资源字符串不带前缀(比如classpath:),ResourceLoader获取资源的行为根据ApplicationContext的类型的不同而不同,比如ClassPathXmlApplicationContext默认会以ClassPathResource的方式获取资源,FileSystemXmlApplicationContext默认会以FileSystemResource的方式获取资源。

ResourcePatternResolver 接口

ResourcePatternResolver接口是ResourceLoader的扩展:

public interface ResourcePatternResolver extends ResourceLoader {

    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    Resource[] getResources(String locationPattern) throws IOException;
}

ResourceLoader的基础上,getResources()方法增加了对通配符的支持:

@RestController
@RequestMapping("/hello")
public class HelloController {
    @Autowired
    private ResourcePatternResolver resourcePatternResolver;

    @GetMapping("")
    public String hello() throws IOException {
        Resource[] resources = resourcePatternResolver.getResources("classpath:*.properties");
        for(Resource r: resources){
            System.out.println(r.getFilename());
        }
        if (resources == null || resources.length == 0){
            return Result.fail("没有获取到文件").toString();
        }
        Resource resource = resources[0];
        printContent(resource);
        return Result.success().toString();
    }
	// ...
}

这个示例中,resourcePatternResolver.getResources("classpath:*.properties")可以匹配到resource目录下所有以.properties为后缀的文件作为资源对象返回。

如果需要从多个jar中检索同样的包名下的资源,可以使用classpath*:这样的前缀配合通配符检索。

ResourceLoaderAware 接口

可以让bean通过实现ResourceLoaderAware接口的方式获取ResourceLoader

@RestController
@RequestMapping("/hello")
public class HelloController implements ResourceLoaderAware {
	// ...
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        Resource resource = resourceLoader.getResource("classpath:override.properties");
        try {
            printContent(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

当然,相比直接注入ResourceLoader,这样做并没有什么优势。

注入Resource

可以借助@Value注解直接注入Resource

@RestController
@RequestMapping("/hello")
public class HelloController implements ResourceLoaderAware {
	// ...
    @Value("${my.properties}")
    @Autowired
    private Resource resource;

    @GetMapping("")
    public String hello() throws IOException {
    	printContent(resource);
        return Result.success().toString();
    }
    // ...
}

Spring Boot默认的配置文件application.properties

my.properties=classpath:override.properties

当然,通过setter或构造器注入也是可以的,这里不再演示。

资源字符串中使用了通配符,可以注入所有匹配的资源:

my.all.properties=classpath:*.properties
@RestController
@RequestMapping("/hello")
public class HelloController implements ResourceLoaderAware {
    // ...
    @Value("${my.all.properties}")
    @Autowired
    private Resource[] resources;

    @GetMapping("")
    public String hello() throws IOException {
        for (Resource r : resources) {
            System.out.println(r.getFilename());
        }
        if (resources == null || resources.length == 0) {
            return Result.fail("没有获取到文件").toString();
        }
        Resource resource = resources[0];
        printContent(resource);
        return Result.success().toString();
    }
    // ...
}

本文所有的示例代码可以通过learn_spring_boot/ch28/resource获取。

谢谢阅读。

参考资料

  • 核心技术 (springdoc.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/523494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【人像抠图】使用vs2022,onnxruntime框架进行部署(视频和多图片处理)

一、人像抠图的应用场景 1. 图像编辑:在图像编辑软件中,人像抠图是常用操作之一。通过抠图可以将人物从原背景中分离出来,放到新背景中,实现人物换背景的效果。这在电影后期特效、游戏角色置换等领域有很广泛的应用。 2. 视频特效:在视频编辑与特效制作中,人像抠图也是关键技术…

Python的标准库argparse讲解

argparse 是 Python 的标准库之一,用于解析命令行参数。通过 argparse,你可以轻松定义你的脚本或应用程序所需的命令行参数,并从命令行中获取这些参数的值。 import argparse# 创建解析器 parser argparse.ArgumentParser()# 添加命令行参数…

【react 全家桶】高级指引(下)

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录 13【react高级指引&#xff08;下&…

是哟Git时报错OpenSSL SSL_read: Connection was reset, errno 10054

文章目录 修改hosts的ip多尝试解除SSL验证 报错如下所示 遇到这个问题首先可以考虑开魔法或者开魔法加换个网比如开手机热点 解除SSL验证我没有试过, 我就在hosts文件中加上了ip的配置就好了 修改hosts的ip 根据网上的教程, 我试了试修改C盘中hosts文件的GitHub相关访问域名的…

QgsPoint类

在 QGIS 中&#xff0c;QgsPoint 类是用于表示二维或三维点的类。它由 X、Y 和 Z 坐标组成&#xff0c;并且可以带有一个可选的 M 值&#xff08;也称为测量值&#xff09;。以下是 QgsPoint 类的主要参数介绍&#xff1a; x&#xff1a;表示点的横向坐标值。y&#xff1a;表示…

在 Windows 上安装 scoop

一、前言 个人主页: ζ小菜鸡大家好我是ζ小菜鸡&#xff0c;让我们一起学习在在 Windows 上安装 scoop。如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连) 二、 scoop是什么 windows下的安装源搜索工具&#xff0c;有点类似centos下的yum和Ubuntu下的apt。用这个拉下来安装…

路径规划算法:基于粒子群优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于粒子群优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于粒子群优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法…

100+套大数据可视化模板

由于公司项目里面用到一个数据可视化大屏页面&#xff0c;自己网上各种谷歌百度&#xff0c;发现资源良莠不齐&#xff0c;而且大多数都是收费的&#xff0c;甚至一个页面一收费的那种。 前前后后自己不管是付费的还是免费的收集了不少&#xff0c;于是自己打算整理下&#xf…

应届生如何在职场中提高竞争力?这些方法和策略不容错过!

当前就业形势严峻&#xff0c;对于即将步入职场的应届生来说&#xff0c;提高自己的竞争力显得尤为重要。那么&#xff0c;要如何提高自己的职场竞争力呢&#xff1f;本文将为你分享一些有效的方法和策略&#xff0c;帮助你在职场中获得更好的发展。 一、提高自身素质 职场中&…

JWT 入门

1.介绍 JSON Web Token&#xff08;JWT&#xff09;是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。该token被设计为紧凑且安全的&#xff0c;特别适用于分布式站点的单点登录&#xff08;SSO…

华为OD机试真题 Java 实现【猜字谜】【2023Q1 100分】

一、题目描述 小王设计了一人简单的清字谈游戏&#xff0c;游戏的迷面是一人错误的单词&#xff0c;比如nesw&#xff0c;玩家需要猜出谈底库中正确的单词。猜中的要求如 对于某个谜面和谜底单词&#xff0c;满足下面任一条件都表示猜中&#xff1a; 变换顺序以后一样的&…

115.【SpringBoot(IDEA)+Vue(Vscode)前后端交互】

SpringBootVue前后端分离 (一)、环境介绍(二)、Vscode部分1.静态资源2.配置route路由和axios异步3.配置跨域支持 (三)、IDEA部分1.创建SpringBoot项目2.创建两个实体类3.创建控制层4.配置后端响应的端口 (四)、Vue和SpringBoot交互1.同时运行IDEA和Vscode2.访问登入界面 (一)、…

C语言——操作符详解

哈喽&#xff0c;大家好&#xff0c;今天我们来学习C语言中的各中操作符。 目录 1.操作符的分类 2.算数操作符 整数的二进制表示 3.位移操作符 3.1左移操作符 3.2右移操作符 4.位操作符 5.赋值操作符 6.单目操作符 6.1 单目操作符介绍 ~ 的用法&#xff1a; 6.2 si…

冰点还原2023中文版最新电脑系统数据恢复软件

冰点还原是什么&#xff1f;对其不了解的用户可能会认为它是《冰雪奇缘》的番外篇或续篇之类的&#xff0c;其实它们俩没有半毛钱关系&#xff0c;它其实是一款系统还原备份软件。冰点还原精灵是一款强大的系统备份、还原、修复软件&#xff0c;可以在极短时间内将系统还原到初…

第十四届蓝桥杯青少组选拔赛Python真题 (2022年11月27日),包含答案

第十四届蓝桥杯青少组选拔赛Python真题 (2022年11月27日) 一、编程题 第 1 题 问答题 输入一个整数N (-100sNs100)输出N10的结果例如: N 5&#xff0c;510 的结果为15 (15-510)[输入描述] 输入一个整数N (-100sNs100) [输出描述] 输出一个整数&#xff0c;表示N10的结果 [样…

【C生万物】 指针篇 (进级) 下

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; &#x1f449; 专栏&#xff1a;《C生万物 | 先来学C》&#x1f448; 前言&#xff1a; 承接上篇&#xff0c;这期继续C语言指针的学习。 目录 Part4:数组参数&指针参数 …

股票量价关系基础知识8----图解各阶段量价关系:价平量增

图解各阶段量价关系&#xff1a;价平量增 价平量增是指在成交量增加的情况下&#xff0c;股价几乎维持在一个价位附近波动。 一、上涨初期的价平量增 &#xff08;一&#xff09;形态分析 在股价上涨的初期&#xff0c;价平量增是筹码良性换手的现象&#xff0c;这可能是主力在…

企业如何提高销售对CRM的使用率

CRM销售管理系统是帮助企业管理销售和客户的工具。它使企业能够跟踪和分析客户行为&#xff0c;管理客户关系&#xff0c;从而提高销售线索转化率。尽管CRM系统有着诸多的好处&#xff0c;但CRM的使用率往往很低&#xff0c;尤其是在销售团队中。为什么CRM使用率低销售不爱用&a…

gradle插件分享-手把手教你写gradle插件

gradle插件分享-手把手教你写gradle插件 写在前面&#xff1a; 在基础熟练的基础上&#xff0c;完全可以考虑基于Booster、ByteX等框架来开发&#xff0c;效率应该会高一些。 修改字节码的插件不止asm一个&#xff0c;还有javaassist等&#xff0c;可以多做一些尝试&#xff…

双令牌机制(chatgpt)

先记录下 双令牌机制主要用于增加Web应用程序的安全性。这种机制通常包括两种类型的令牌&#xff1a;访问令牌&#xff08;Access Token&#xff09;和刷新令牌&#xff08;Refresh Token&#xff09;。 1&#xff0e;访问令牌:访问令牌是用户完成身份验证后接收的令 牌&…