自定义SpringBoot读取jar文件

本文详细介绍了Spring中Resource接口的实现类及其用途,如UrlResource、ClassPathResource、FileSystemResource等,以及如何通过ResourceLoader加载资源。针对在Spring Boot jar包中获取资源文件子目录、处理FileNotFoundException等问题,提出了解决方案,例如使用PathMatchingResourcePatternResolver。同时,文章还展示了如何根据已知文件名和目录加载资源,并给出了示例代码。

内置 Resource 接口实现

ResouceUtils

ResouceUtils.getFile()是专门用来加载非压缩和Jar包文件类型的资源,所以它根本不会去尝试加载Jar中的文件,要想加载Jar中的文件,只要用可以读取jar中文件的方式加载即可,比如 xx.class.getClassLoader().getResouceAsStream()这种以流的形式读取文件的方式,所以使用读取文件流就可以拿到了。

UrlResource

UrlResource 封装了 java.net.URL,可用于访问通过 URL 访问的任何对象,比如文件、HTTP 资源、FTP 资源等等。所有 URL 都有一个标准化的字符串表示,因此可以使用适当的标准化前缀来表示不同 URL 类型的 URL。一般支持如下资源访问。

new UrlResource("file:d/xxx.txt");
new UrlResource("http://地址");
new UrlResource("ftp://地址");

ClassPathResource

ClassPathResource 表示从类路径获取资源,它使用线程上下文类加载器、给定的类加载器来加载资源。classpath 资源存在于类路径中的文件系统中或 jar 包里。

ClassPathResource 常用构造器

public ClassPathResource(String path);
public ClassPathResource(String path, @Nullable ClassLoader classLoader);
public ClassPathResource(String path, @Nullable Class<?> clazz);
 
public ClassPathResource(String path):使用默认的类加载器记载 path 类路径下的资源
public ClassPathResource(String path, @Nullable ClassLoader classLoader):使用指定的类加载器加载 path 类路径下的资源
public ClassPathResource(String path, @Nullable Class clazz):只用指定的类加载 path 类路径下的资源

FileSystemResource

FileSystemResource 是 Resource 实现支持 java.io 和 java.nio.file.Path 的处理。

ServletContextResource

ServletContextResource 是 web 应用资源,ServletContext 资源的实现。用于简化 servlet 容器的 ServletContext 接口的 getResource 操作和 getResourceAsStream 操作。

InputStreamResource

InputStreamResource 是基于 InputStream 的实现,参数是一个 InputStream 只有在没有特定场景下的 Resource 的时候才使用它。

ByteArrayResource

ByteArrayResource 是给定一个 byte[] 数组的实现创建 ByteArrayInputStream。

ResourceLoader

ResourceLoader 用于返回 Resource 的实例。

public interface ResourceLoader {
    Resource getResource(String location);
}

Spring 的 ApplicationContext 都实现了 ResourceLoader

  1. ClassPathXmlApplicationContext
  2. FileSystemXmlApplicationContext
  3. WebApplicationContext

因此可以使用 ApplicationContext 来获取资源实例,当在某个 ApplicationContext 实现类中调用 getResource 而参数没有指定特定的资源前缀时,将返回适合 ApplicationContext 实现实例的资源类型,下面是 ClassPathXmlApplicationContext 的执行代码

Resource template = ctx.getResource("some/resource/path/myTemplate.txt");

对于 ClassPathXmlApplicationContext 以上代码返回一个 ClassPathResource。
如果对 FileSystemXmlApplicationContext 实例执行相同的方法,它将返回FileSystemResource。对于 WebApplicationContext,它将返回一个 ServletContextResource。

另外也可以指定资源前缀比如 classpath: 强制使用 ClassPathResource 无论 ApplicationContext 实现实例类型是什么。

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

也可以使用其他前缀

Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");

getResource 字符串参数对象转换为资源对象的策略

资源前缀示例说明
classpath:classpath:com/myapp/config.xml从 classpath 类路径加载
file:file:///data/config.xml从文件系统中作为 URL 加载
http:https://myserver/logo.png作为 URL 加载
(none)/data/config.xml根据 ApplicationContext 实现实例加载

classpath 和 classpath 区别*

classpath:用于加载类路径(包括jar包)中的一个且仅一个资源;对于多个匹配的也只返回一个。
classpath* :用于加载类路径(包括jar包)中的所有匹配的资源。

问题

1、如何获取 SpringBoot jar 包中的指定文件夹下的资源文件子目录?

借助 Spring 提供的 PathMatchingResourcePatternResolver 类得以解决。

2、获取文件路径时 resource.getFile().getPath() 为啥出现 FileNotFoundException?

SpringBoot 没办法通过 File 的形式访问 jar 包里面的文件,借助 resource.getURL().getPath() 获取当前资源对应的URL的路径得以解决。

3、若已知道要加载的资源文件的名称与目录,该怎么加载呢?

Xxx.getClass().getResourceAsStream(“”)

例子

private static final String EXTENSIN_KEY = "key";
private static final String EXTENSIN_PROPERTIES = "properties";
 
 
public static boolean initEnv() {
    try {
        Map<String, Map<String, InputStream>> resourceMap = Maps.newHashMap();
 
 
        // 1. 定义资源匹配规则,会在所有的JAR包的根目录下搜索指定文件
        String matchPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "/cool/*/*.*";
        // 2. 返回指定路径下所有的资源对象(子目录下的资源对象)
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resourcePatternResolver.getResources(matchPattern);
        for (Resource resource : resources) {
            // 3. 获取文件名称
            String fileFlag = resource.getFilename().endsWith(EXTENSIN_KEY) ? EXTENSIN_KEY : EXTENSIN_PROPERTIES;
            // 4. 获取子目录名称
            String[] filePathAry = resource.getURL().getPath().split("/");
            String mb = filePathAry[filePathAry.length - 2];
            Map<String, InputStream> mbMap = resourceMap.get(mb);
            if (MapUtils.isEmpty(mbMap)) {
                mbMap = Maps.newHashMap();
                resourceMap.put(mb, mbMap);
            }
            mbMap.put(fileFlag, resource.getInputStream());
        }
        // 5. 封装资源文件流的Map
        Map<InputStream, InputStream> map = Maps.newHashMap();
        resourceMap.forEach((mainBody, inputStreamMap) -> {
            map.put(inputStreamMap.get(EXTENSIN_KEY), inputStreamMap.get(EXTENSIN_PROPERTIES));
        });
    } catch (Exception e) {
        return false;
    }
 
 
    // ... ...
    // 采用 map 进行后续特殊操作(省略)
    // ... ...
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梁晓山(ben)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值