美文网首页Java技术分享项目管理经验总结
SpringBoot打jar包或war包获取不到资源文件解决办法

SpringBoot打jar包或war包获取不到资源文件解决办法

作者: 不学无数的程序员 | 来源:发表于2018-11-06 16:12 被阅读4次

    问题描述

    在开发过程中我们经常会碰到要在代码中获取资源文件的情况,而我在最近将原有的Tomcat的原生项目迁移到SpringBoot项目中时碰到一个问题,就是在本地运行时,获取本地的xml资源文件是能够获取到的,但是项目打成war包然后将其部署到Tomcat中运行时,就会发生问题,报找不到资源文件的错误。然后经过寻找排查确定了是下面代码通过ClassLoader获取路径的时候出错了。

    ExcelXmlModelFactory.class.getClassLoader().getResource("template/").getPath()
    
    

    我的资源文件存放路径如下

    image

    在本地中打印的日志路径为

    /Users/hupengfei/git/lap/lap-service/out/production/resources/template
    
    

    但是在将SpringBoot打包成war包部署到Tomcat中时打印的目录为

    /home/app/lap/app/lap-service-1.0.0-SNAPSHOT.war!/WEB-INF/classes!/template/
    
    

    可以看到在Linux中无法直接访问未经解压的文件,所以就会找不到文件。

    解决办法

    通过ClassLoadergetResourceAsStream()方法获取其流,就能够获取到

    读取jar里面的文件,我们只能用流去读取,不能用File

    获取资源的两种方式

    通常在开发过程中会碰到读取配置文件的问题,一般有两种方式进行读取。一种是Class.getResource(String path),一种是ClassLoader.getResource(String path),这两种虽然都能读取文件,但是在path的填写上有一点点的不同。

    Class.getResource

    • path以/开头:则是从ClassPath根下获取
    • path不以/开头:默认是从此类所在的包下取资源

    下面有个例子

    public class Test {
        public static void main(String[] args) {
             System.out.println(Test.class.getResource("/"));
            System.out.println(Test.class.getResource(""));
        }
    }
    
    

    输出如下

    file:/Users/hupengfei/git/Test/out/production/classes/
    file:/Users/hupengfei/git/Test/out/production/classes/Practice/Day13/
    

    那么如果在resource下有三个资源文件

    image

    那么该怎么获取这三个文件呢,因为在class文件夹中的目录结构如下

    -- classes
        -- Convience
        -- Practice
        -- Test
    

    所以如果想要获取Test下的资源文件,就如下的获取方法

    System.out.println(Test.class.getResource("../../Test/1.xml"));
    System.out.println(Test.class.getResource("/Test/1.xml"));
    

    ClassLoader.getResource

    ClassLoader.getResource的path中不能以/开头,path是默认是从根目录下进行读取的

    例子如下

    System.out.println(Test.class.getClassLoader().getResource(""));
    System.out.println(Test.class.getClassLoader().getResource("/"));
    

    打印如下

    file:/Users/hupengfei/git/Test/out/production/classes/
    null
    

    从上面例子我们可以看到

    Test.class.getClassLoader().getResource("")=Test.class.getResource("/")

    两个获取资源文件的差别

    其实查看Class.getResource中可以看到

        public java.net.URL getResource(String name) {
            name = resolveName(name);
            ClassLoader cl = getClassLoader0();
            if (cl==null) {
                // A system class.
                return ClassLoader.getSystemResource(name);
            }
            return cl.getResource(name);
        }
    
    

    他最后调用的还是ClassLoader.getResource这个方法,那么为什么会有path的差别呢,因为其resolveName方法中对传的/进行了解析,解析为了空字符串。

        private String resolveName(String name) {
            if (name == null) {
                return name;
            }
            if (!name.startsWith("/")) {
                Class<?> c = this;
                while (c.isArray()) {
                    c = c.getComponentType();
                }
                String baseName = c.getName();
                int index = baseName.lastIndexOf('.');
                if (index != -1) {
                    name = baseName.substring(0, index).replace('.', '/')
                        +"/"+name;
                }
            } else {
                name = name.substring(1);
            }
            return name;
        }
    
    

    可以看到在这穿进去的为/

    image

    传出的是

    image

    参考文章

    相关文章

      网友评论

        本文标题:SpringBoot打jar包或war包获取不到资源文件解决办法

        本文链接:https://www.haomeiwen.com/subject/qrmuxqtx.html