返回顶部
首页 > 资讯 > 精选 >如何解决基于ClasspathResource路径问题
  • 260
分享到

如何解决基于ClasspathResource路径问题

2023-06-20 21:06:01 260人浏览 安东尼
摘要

小编给大家分享一下如何解决基于ClasspathResource路径问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!ClasspathResource路径问题前

小编给大家分享一下如何解决基于ClasspathResource路径问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

ClasspathResource路径问题

前言

项目中工程以SpringBoot jar形式发布,跟之前容器比少了一个解压目录,这个过程中出现了ClasspathResource的文件获取问题。具体如下:

故障情况

本地springboot工程打成jar包发布,在以下代码r.getFile()获取类目录下模板excel文件报错:

cannot be resolved to absolute file path because it does not reside in the file system: jar

如何解决基于ClasspathResource路径问题

解决方案

调整代码,直接获取对应的文件流,进行封装。

如何解决基于ClasspathResource路径问题

ClassPathResource详解

ClassPathReource resource=new ClassPathResource("spring_beans.xml");

1:public class ClassPathResource extends AbstractFileResolvingResource

在ClassPathResource中,含参数String path的构造函数:

public ClassPathResource(String path ) {         this (path , (ClassLoader) null);    }

2:上述构造函数指向了另外一个构造函数:

public ClassPathResource (String path , ClassLoader classLoader ) {        Assert. notNull(path, "Path must not be null");        String pathToUse = StringUtils.cleanPath(path);         if (pathToUse .startsWith("/")) {             pathToUse = pathToUse .substring(1);        }         this .path = pathToUse;         this .classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());    }

能够看到path由StringUtils的cleanPath方法返回了pathToUse。由此,我们找到StringUtils的cleanPath方法

3:public abstract class StringUtils

public static String cleanPath (String path ) {         if (path == null) {             return null ;        }        String pathToUse = replace( path , windows_FOLDER_SEPARATOR , FOLDER_SEPARATOR);         int prefixIndex = pathToUse .indexOf(":" );        String prefix = "" ;         if (prefixIndex != -1) {             prefix = pathToUse .substring(0, prefixIndex + 1);             pathToUse = pathToUse .substring(prefixIndex + 1);        }         if (pathToUse .startsWith(FOLDER_SEPARATOR)) {             prefix = prefix + FOLDER_SEPARATOR;             pathToUse = pathToUse .substring(1);        }         String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR );        List<String> pathElements = new LinkedList<String>();         int tops = 0;          for (int i = pathArray. length - 1; i >= 0; i --) {            String element = pathArray [i ];             if (CURRENT_PATH .equals(element)) {                 // Points to current directory - drop it.            }             else if (TOP_PATH.equals(element)) {                 // ReGIStering top path found.                 tops ++;            }             else {                 if (tops > 0) {                     // Merging path element with element corresponding to top path.                     tops --;                }                 else {                     // NORMal path element found.                     pathElements .add(0, element );                }            }        }          // Remaining top paths need to be retained.         for (int i = 0; i < tops; i++) {             pathElements .add(0, TOP_PATH);        }          return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR );    }

4:StringUtils类中 replace方法

public static String replace (String inString , String oldPattern , String newPattern ) {         if (!hasLength( inString ) || !hasLength(oldPattern) || newPattern == null ) {             return inString ;        }        StringBuilder sb = new StringBuilder();         int pos = 0; // our position in the old string         int index = inString .indexOf(oldPattern );         // the index of an occurrence we've found, or -1         int patLen = oldPattern.length();         while (index >= 0) {             sb.append( inString .substring(pos , index ));             sb.append( newPattern );             pos = index + patLen;             index = inString .indexOf(oldPattern, pos );        }         sb.append( inString .substring(pos ));         // remember to append any characters to the right of a match         return sb .toString();    }

5:StringUtils类类中的hasLength方法

由此可以看出,同样的方法名,不同的方法签名,然后在其中一个方法中引用另外一个方法。好多类都是这么用的,就像开始的时候的构造函数那样,虽然不知道好处 是什么,但先记下来。

public static boolean hasLength (String str ) {         return hasLength((CharSequence) str);    }    public static boolean hasLength (CharSequence str) {         return (str != null && str.length() > 0);    }

跟踪到这里,可以知道hasLength方法的目的就是str不为空且str的长度大于0。突然发现CharSequence这个类没接触过,来看一下它的源码

6:public interface CharSequence{}

额,源码没看懂 就不粘贴过来了。

7:回到StringUtils的replace方法

首先判断传入的三个参数,如果为空后者长度小于0,直接返回inString;那么我看一下这三个参数都是什么:

inString:path 这个就是我们传入的文件名

oldPattern:private static final String WINDOWS_FOLDER_SEPARATOR = "\\";

newPattern:private static final String FOLDER_SEPARATOR = "/" ;这两个是文件分隔符

然后给局部变量index赋值,通过查阅api

public int indexOf(int ch)

返回指定字符在此字符串中第一次出现处的索引

意思就是在path中查找"\\",例如我写文件的绝对路径是D:\\文件\\API\\jdk_API_1_6_zh_CN.CHM,我就需要循环的读取“\\”,接下来while循环中出现了substring方法,继续查阅API:

public String substring(int beginIndex)

返回一个新的字符串,它是此字符串的一个子字符串。该子字符串从指定索引处的字符开始,直到此字符串末尾。

public String substring(int beginIndex,                        int endIndex)

返回一个新字符串,它是此字符串的一个子字符串。该子字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该子字符串的长度为 endIndex-beginIndex

故此 ,第一次循环会把path路径中从0索引开始,直到第一个"\\"之间的内容添加到StringBuffer中,然后再在StringBuffer中添加“/”,接下来pos和index都需要改变,要往后挪。因为循环需要往后走,我们要找到第二个“\\”,觉得这个有点算法的意思。返回sb.toString()。

总结一下replace方法,本意是根据传入的路径path,如果是D:\\文件\\API\\JDK_API_1_6_zh_CN.CHM这种格式的,给转换成D:/文件/API/JDK_API_1_6_zh_CN.CHM这种格式。

8:StringUtils的cleanPath方法:

通过replace的返回值,我们得到了可以用的路径pathToUse,然后我们要把这个路径下“:”给找出来,正如代码

int prefixIndex = pathToUse.indexOf(":" );

那样,需要知道,indexOf方法只要没找到相应的字符,就会返回-1,所以在下面的判断中才会以perfixIndex是否为-1来进行判断。如果路 径中有“:”,接着以D:/文件/API/JDK_API_1_6_zh_CN.CHM举例,prefix="D:" pathToUse="/文件/API/JDK_API_1_6_zh_CN.CHM ",这个很有意思,因为程序不知道我们输入的是绝对路径 带D:的这种 ,还是/开头的这种,或者说相对路径,程序直接全给你判断了。

接下来会判断pathToUse是否以“/"开头,是的话prefix会加上“/”,现在的prefix有两种情况,可能是"D:/"这种,也可能是"/"这种,而pathToUse肯定是“文件/API/JDK_API_1_6_zh_CN.CHM ”这种了。

String[] pathArray = delimitedListToStringArray( pathToUse, FOLDER_SEPARATOR );

看到这句代码,我估计是把pathToUse给拆成字符串数组里,就像是这样,文件 API ***的这种。接下来看看具体的代码是不是这样:

9:StringUtils的delimitedListToStringArray方法

public static String[] delimitedListToStringArray(String str, String delimiter) {         return delimitedListToStringArray( str, delimiter, null );    }     public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete ) {         if (str == null) {             return new String[0];        }         if (delimiter == null) {             return new String[] {str};        }        List<String> result = new ArrayList<String>();         if ("" .equals(delimiter)) {             for (int i = 0; i < str.length(); i++) {                 result.add(deleteAny( str.substring(i , i + 1), charsToDelete));            }        }         else {             int pos = 0;             int delPos ;             while ((delPos = str.indexOf(delimiter , pos )) != -1) {                 result.add(deleteAny( str.substring(pos , delPos), charsToDelete ));                 pos = delPos + delimiter.length();            }             if (str .length() > 0 && pos <= str.length()) {                 // Add rest of String, but not in case of empty input.                 result.add(deleteAny( str.substring(pos ), charsToDelete));            }        }         return toStringArray( result);    }

先看看传入的参数:

str:pathToUse,就是文件/API/JDK_API_1_6_zh_CN.CHM                    delimiter:"/"                    charsToDelete:null
public static String deleteAny(String inString, String charsToDelete ) {         if (!hasLength( inString) || !hasLength(charsToDelete)) {             return inString ;        }        StringBuilder sb = new StringBuilder();         for (int i = 0; i < inString.length(); i++) {             char c = inString.charAt( i);             if (charsToDelete .indexOf(c) == -1) {                 sb.append( c);            }        }         return sb .toString();    }

如果说我们传入的"/"等于""的话,显然是不可能,我们所假如的话,会把pathTOUse倒着循环,每个字符都摘出来,然后当成字符串用,传入deleteAny中,然后又是循环,对每个字符而言,如果charsToDelete中没有这个字符,就在StringBuilder中添加这个字符。返回值是String。当然了,这个还没用到。我们用到的是那个很复杂的else

我们遇到了一个循环,对pathToUse而言,从索引0开始,如果pathToUse中有"/",就像文件/API/JDK_API_1_6_zh_CN.CHM 我们会得到“文件,然后还会进入deleteAny这个方法,参数inString就是"文件",charsToDelete是null,突然发现charsToDelete的值为Null的话会直接返回InString,也就是“文件”。

返回到delimitedListToStringArray方法之后,接着往后循环,最终的结果就是实现了把pathToUse给切割成若干个String的形式。

10:回到StringUtils的cleanPath方法

我们遇到了一个倒着的循环,如果说我们这个是特别正常的路径,就相当于复制了,如果是以.或者..结尾的这些内容,我们就把它给忽略了。

我得承认上面这些过程真的好复杂,其实就是做了一件事,对输入的路径进行了处理,只不过考虑的情况多了一点。所以我决定还是用debug来走一遍看看。

这时我用的是绝对路径

终于熬到了这个方法的结束。

11:回到ClassPathResource的构造函数

this .classLoader = ( classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());

如果传入的classLoaser有值,就返回这个值,如果没有,就获取一个。

public static ClassLoader getDefaultClassLoader() {        ClassLoader cl = null;         try {             cl = Thread.currentThread().getContextClassLoader();        }         catch (Throwable ex ) {             // Cannot access thread context ClassLoader - falling back...        }         if (cl == null) {             // No thread context class loader -> use class loader of this class.             cl = ClassUtils.class .getClassLoader();             if (cl == null) {                 // getClassLoader() returning null indicates the bootstrap ClassLoader                 try {                     cl = ClassLoader.getSystemClassLoader();                }                 catch (Throwable ex ) {                     // Cannot access system ClassLoader - oh well, maybe the caller can live with null...                }            }        }         return cl ;    }

写到这,我们的ClassPathResouce resouce实例就有了path 和 classLoader这两个关键属性。

如果我们想获取输入流

@Override    public InputStream getInputStream() throws IOException {        InputStream is;         if (this .clazz != null) {             is = this.clazz .getResourceAsStream(this. path);        }         else if (this.classLoader != null) {             is = this.classLoader .getResourceAsStream(this. path);        }         else {             is = ClassLoader.getSystemResourceAsStream( this.path );        }         if (is == null) {             throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");        }         return is ;    }

会判断clazz 有没有值,classLoader有没有值,然后再获取输入流。前两天整理了java.lang.Class这个类的意思,现在就能用一点了,先看看定义的一些属性

private final String path ;     private ClassLoader classLoader;     private Class<?> clazz;

ClassPathResource有好几个构造函数,有的构造函数会传入classLoader,有的会传入clazz,这个clazz就是相应的类在JVM上的实例,显然上面的例子中并没有这个东西,而classLoader是有的,所以通过classLoader获取输入流。

我觉得对ClassPathResource理解的更透彻了,虽然大部分时间都是在对path进行处理。

近期还要看看ClassLoader,还不是很清楚它的工作机制。

以上是“如何解决基于ClasspathResource路径问题”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: 如何解决基于ClasspathResource路径问题

本文链接: https://lsjlt.com/news/300195.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何解决基于ClasspathResource路径问题
    小编给大家分享一下如何解决基于ClasspathResource路径问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!ClasspathResource路径问题前...
    99+
    2023-06-20
  • 基于ClasspathResource路径问题的解决
    ClasspathResource路径问题 前言 在项目中工程以springboot jar形式发布,跟之前容器比少了一个解压目录,这个过程中出现了ClasspathResource...
    99+
    2024-04-02
  • Git的路径问题如何解决?
    Git是一款非常流行的版本控制工具,可以让我们更方便地管理代码。在使用Git的过程中,有时候会遇到路径问题,比如说在使用Git命令时,路径不正确,导致无法执行操作。这篇文章将介绍Git路径问题的解决方法,并提供一些演示代码帮助读者更好地理...
    99+
    2023-09-30
    path shell git
  • 如何解决Jupyter文件路径的问题
    这篇文章给大家分享的是有关如何解决Jupyter文件路径的问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在使用Jupyter notebook时有这么一句代码start_frame = i...
    99+
    2023-06-14
  • NumPy路径问题:如何在PHP中解决?
    NumPy是一款强大的Python数学库,它提供了大量的数学函数和工具,可以帮助我们快速、高效地进行数值计算和数据分析。然而,在使用NumPy时,有时候会遇到一些路径问题,特别是在使用PHP调用NumPy时更为常见。那么,如何在PHP中解决...
    99+
    2023-09-11
    numpy path numy
  • NumPy 和 PHP 的路径问题如何解决?
    NumPy 和 PHP 是非常常用的数据处理和 web 开发工具。然而,在使用这两种工具时,我们经常会遇到路径问题。本文将会介绍如何解决 NumPy 和 PHP 中的路径问题,并提供一些实例代码供读者参考。 一、NumPy 路径问题解决方...
    99+
    2023-08-01
    path 打包 numpy
  • Java的路径问题:如何快速解决?
    Java是一种十分流行的编程语言,它的使用范围非常广泛,但是在编写Java程序的过程中,难免会遇到一些路径问题。这些问题可能会让你的程序无法正常运行,因此解决Java的路径问题非常重要。在本文中,我们将介绍Java路径问题的解决方法,并提供...
    99+
    2023-08-15
    path bash http
  • logback日志文件路径问题如何解决
    这篇文章给大家介绍logback日志文件路径问题如何解决,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。对于J2SE项目,当前路径为工程所在目录如我的工程为:D:\test则使用…/logs生成的日志文件位于:D:\lo...
    99+
    2023-06-06
  • python-docx文件路径问题的如何解决
    本篇内容主要讲解“python-docx文件路径问题的如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python-docx文件路径问题的如何解决”吧!path = "test....
    99+
    2023-06-09
  • 基于springboot redirect重定向路径问题总结
    目录SpringMVC重定向视图RedirectView小分析前言实例讲解Controller代码我们通过firebug看下路径:总结SpringMVC重定向视图RedirectVi...
    99+
    2024-04-02
  • JavaWeb路径问题怎么解决
    这篇文章主要介绍“JavaWeb路径问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JavaWeb路径问题怎么解决”文章能帮助大家解决问题。要知道我们在i...
    99+
    2024-04-02
  • PHP编程算法:如何解决HTTP路径中的路径参数问题?
    在Web开发中,我们经常需要从URL中获取参数来完成一些操作。对于查询参数(query string),PHP提供了$_GET和$_POST两个超全局变量来获取,但是对于路径参数(path parameter),PHP并没有提供直接获取的...
    99+
    2023-08-18
    编程算法 http path
  • 如何解决vue :src 文件路径错误问题
    这篇文章主要介绍了如何解决vue :src 文件路径错误问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。首先先说明下vue-cli的ass...
    99+
    2024-04-02
  • 如何解决laydate.js加载laydate.css路径错误问题
    小编给大家分享一下如何解决laydate.js加载laydate.css路径错误问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧...
    99+
    2024-04-02
  • ASP IDE路径并发:如何解决性能问题?
    在ASP IDE开发过程中,路径并发是一个常见的性能问题。当多个用户同时访问同一路径时,服务器会出现瓶颈,导致页面响应变慢甚至崩溃。本文将介绍如何解决ASP IDE路径并发的性能问题。 一、使用Session变量 Session变量可以在...
    99+
    2023-10-11
    ide path 并发
  • Java IDE中的路径加载问题如何解决?
    Java是一种面向对象、跨平台的编程语言,而Java开发环境(IDE)是开发者开发Java程序的必备工具之一。然而,当我们在IDE中开发Java程序时,常常会遇到路径加载问题,这会使得程序无法正常运行。本文将介绍Java IDE中常见的路...
    99+
    2023-07-23
    ide path load
  • 如何使用 PHP 和 JavaScript API 解决路径问题?
    在开发 Web 应用程序时,路径问题是一个常见的问题。路径问题通常是由于不同操作系统、不同 Web 服务器和不同的文件系统之间的差异引起的。在本文中,我们将介绍如何使用 PHP 和 JavaScript API 解决路径问题。 PHP 路...
    99+
    2023-11-10
    api javascript path
  • C#路径问题中的如何保存问题的解决方法
    本篇内容主要讲解“C#路径问题中的如何保存问题的解决方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#路径问题中的如何保存问题的解决方法”吧!C#路径问题之保存路径的提问我在项目里建立了一个...
    99+
    2023-06-18
  • 基于SpringBoot启动类静态资源路径问题
    目录SpringBoot启动类静态资源路径SpringBoot核心配置类分别是一下四个静态资源路径静态文件存放位置设置默认配置自定义位置SpringBoot启动类静态资源路径 Spr...
    99+
    2024-04-02
  • dedecms 解决rss相对路径问题
    有些朋友会遇到这样的问题,这个也是织梦的bug。那么下面我们就开始讲解如何进行解决。 我们找到 模版文件templets/plus/rss.htm 地址改成你的就可以了 <link>{dede:field n...
    99+
    2022-06-12
    rss 相对路径
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作