SpringBoot读取war包jar包Resource资源文件解决办法

场景描述

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

  1. /**
  2. * @author mazhq
  3. * @Title: TestMain
  4. * @ProjectName: zeus
  5. * @Description: TODO
  6. * @date 2019/3/5 16:10
  7. */
  8. public class TestMain {
  9. public static void main(String[] args) {
  10. String path = TestMain.class.getClassLoader().getResource("1.xml").getPath();
  11. System.out.println(path);
  12. }
  13.  /**
  14. * 输出:
  15. *
  16. */D:/demo_projects/sc-architecture/service-hi/target/classes/1.xml
  17. */
  18. }

  

但是在将SpringBoot打包放到Linux服务器启动打印的目录为

  1. /data/zeus/service-hi-1.0.0-SNAPSHOT.war!/WEB-INF/classes!/1.xml

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

解决办法

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

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

  1. public class TestMain {
  2. public static void main(String[] args) {
  3. try {
  4. List<String> content = IOUtils.readLines(TestMain.class.getClassLoader().getResourceAsStream("1.xml"), "UTF-8");
  5. } catch (IOException e) {
  6. e.printStackTrace();
  7. }
  8. }
  9. }

  2. 采用绝对路径将文件放到服务器某个路径,在application.properties中配置路径读取。

  3. 不推荐:将内容放到数据库中。

获取资源的两种方式

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

Class.getResource

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

下面有个例子

  1. public class TestMain {
  2. public static void main(String[] args) {
  3. System.out.println(TestMain.class.getResource("/"));
  4. System.out.println(TestMain.class.getResource(""));
  5. }
  6. /**
  7. * 输出:
  8. *
  9. * file:/D:/demo_projects/sc-architecture/service-hi/target/classes/
  10. * file:/D:/demo_projects/sc-architecture/service-hi/target/classes/com/mazhq/servicehi/
  11. */
  12. }

  

那么读取在resource下的1.xml,就如下的获取方法

  1. public class TestMain {
  2. public static void main(String[] args) {
  3. System.out.println(TestMain.class.getResource("/1.xml"));
  4. System.out.println(TestMain.class.getResource("../../../1.xml"));
  5. }
  6. /**
  7. * 输出:
  8. *
  9. * file:/D:/demo_projects/sc-architecture/service-hi/target/classes/1.xml
  10. * file:/D:/demo_projects/sc-architecture/service-hi/target/classes/1.xml
  11. */
  12. }

ClassLoader.getResource

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

代码如下:

  1. public class TestMain {
  2. public static void main(String[] args) {
  3. System.out.println(TestMain.class.getClassLoader().getResource(""));
  4. System.out.println(TestMain.class.getClassLoader().getResource("/"));
  5. }
  6. /**
  7. * 输出:
  8. *
  9. * file:/D:/demo_projects/sc-architecture/service-hi/target/classes/
  10. * null
  11. */
  12. }

  

从上面例子我们可以看到

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

两个获取资源文件的差别

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

  1. public java.net.URL getResource(String name) {
  2. name = resolveName(name);
  3. ClassLoader cl = getClassLoader0();
  4. if (cl==null) {
  5. // A system class.
  6. return ClassLoader.getSystemResource(name);
  7. }
  8. return cl.getResource(name);
  9. }

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

resolveName 方法实现如下:

  1. private String resolveName(String name) {
  2. if (name == null) {
  3. return name;
  4. }
  5. if (!name.startsWith("/")) {
  6. Class<?> c = this;
  7. while (c.isArray()) {
  8. c = c.getComponentType();
  9. }
  10. String baseName = c.getName();
  11. int index = baseName.lastIndexOf('.');
  12. if (index != -1) {
  13. name = baseName.substring(0, index).replace('.', '/')
  14. +"/"+name;
  15. }
  16. } else {
  17. name = name.substring(1);
  18. }
  19. return name;
  20. }
  21.  
  22.   //传入 "/" 返回  ""

  

最后:大家用的时候注意一下这些问题,避免在这个上面耽误时间。

SpringBoot读取war包jar包Resource资源文件解决办法的更多相关文章

  1. springboot的war和jar包

    本篇和大家分享的是通过maven对springboot中打war包和jar包:war通常来说生成后直接放到tomcat的webapps下面就行,tomcat配置自动解压war,而jar一般通过命令行部 ...

  2. 关于war包 jar包 ear包 及打包方法

    关于war包 jar包 ear包 及打包方法 war包:是做好一个web应用后,通常是网站打成包部署到容器中 jar包:通常是开发的时候要引用的通用类,打成包便于存放管理. ear包:企业级应用 通常 ...

  3. Maven pom.xml 配置说明: 打jar包不包括指定资源文件和.class xml,配置不跑testCase,建pom父子项目

    **maven如何配置打jar包时,一些class 或者资源文件不打进来,把classpath的xml文件打进jar <build> <!--针对资源文件--> <res ...

  4. war,jar包是啥

    http://www.blogjava.net/athrunwang/archive/2011/11/18/364191.html 经常听开发说war,jar,car,这些是个什么东东呢? .jar  ...

  5. SpringBoot快速引入第三方jar包

    工作中,我们常会用到第三方jar包,而这些jar包往往在maven仓库是搜不到的,下面推荐一种简单.快速的引入第三方依赖的方法: 比如第三方jar包在lib文件夹下,对pom.xml的配置如下: &l ...

  6. 【Maven】项目打包-war包-Jar包[IDEA将项目打成war包]

    [Maven]项目打包-war包-Jar包[IDEA将项目打成war包] 2017年01月31日 00:21:06 阅读数:22912 标签: ideamaven发布博客插件 更多 个人分类: ❷ J ...

  7. maven将自己的springboot项目打包成jar包后,作为工具包引入其他项目,找不到jar中的类

    将springboot项目打包成jar包,作为工具包导入项目后,找不到jar中的类. 原因是:springboot项目使用了自动的打包插件. 原先的插件配置: <build> <pl ...

  8. 【转】Android中引入第三方Jar包的方法(java.lang.NoClassDefFoundError解决办法)

    原文网址:http://www.blogjava.net/anchor110/articles/355699.html 1.在工程下新建lib文件夹,将需要的第三方包拷贝进来.2.将引用的第三方包,添 ...

  9. (转)Maven依赖的jar包下载不了、jar更新不了的解决办法

    场景一: 使用Maven的同学可能偶尔会遇到这种情况:pom.xml中依赖了项目需要的某个jar文件,但是使用Maven –> update project 还是没办法下载该jar到项目中,你可 ...

随机推荐

  1. Visual Studio 2013旗舰版KEY

    Visual Studio 2013旗舰版KEY:BWG7X-J98B3-W34RT-33B3R-JVYW9

  2. Python 迭代器切片

    函数itertools.islice() 正好适用于在迭代器和生成器上做切片操作 >>> def count(n): ... while True: ... yield n ... ...

  3. Java代码质量度量工具大阅兵

    FindBugs FindBugs, a program which uses static analysis to look for bugs in Java code. It is free so ...

  4. Linux学习笔记之passwd:Authentication token manipulation error_错误的解决办法

    如果在linux中,不管是root用户还是普通用户登录后,修改自己的密码,出现—passwd:Authentication token manipulation error—错误的解决办法: root ...

  5. Python入门之python可变对象与不可变对象

    本文分为如下几个部分 概念 地址问题 作为函数参数 可变参数在类中使用 函数默认参数 类的实现上的差异 概念 可变对象与不可变对象的区别在于对象本身是否可变. python内置的一些类型中 可变对象: ...

  6. nw.exe开发DEMO下载

    参考的原文链接:http://www.jianshu.com/p/7c66ee28ce51 最后,开发者怕你怀疑nw.js的强大,又提供了几个Demo和许多成功的案例来打消我们的顾虑.

  7. 20145301 赵嘉鑫 《网络对抗》Exp6 信息搜集与漏洞扫描

    20145301赵嘉鑫<网络对抗>Exp6 信息搜集与漏洞扫描 基础问题回答 哪些组织负责DNS,IP的管理? 全球根服务器均由美国政府授权的ICANN统一管理,负责全球的域名根服务器.D ...

  8. [c/c++]指针(4)

    现在讲一下指针的主要用途和常见错误. [用途] 1.用作形参 首先,常见新手写交换函数: void swap(int a,int b){ int t = a; a = b; b = t; } 主函数里 ...

  9. topcoder srm 620 div1

    problem1 link 分别计算可以得到(a,b)的有哪些二元组,以及可以得到(c,d)的有哪些二元组.然后在公共的二元组中找到和最大的即可. problem2 link 设最后的排序为$r=[2 ...

  10. 【自动化】基于Spark streaming的SQL服务实时自动化运维

    设计背景 spark thriftserver目前线上有10个实例,以往通过监控端口存活的方式很不准确,当出故障时进程不退出情况很多,而手动去查看日志再重启处理服务这个过程很低效,故设计利用Spark ...