SpringBoot读取resource或template中的文件

Spring-Boot读取resource或template中的文件

1.项目场景:

以jar包方式部署系统,想读取resource或是template下面的文件时,报 File Not Found
我遇到的情况是,整个项目达成了一个包,在开发环境(windows + idea)读取文件没问题,但在预发布环境(centos, 打成一个jar部署),则报错。


2.问题描述:

File file = ResourceUtils.getFile("classpath:templates/jumppage.html")

使用上述方法读取模板文件当部署成jar包时读取不到文件


3.解决方案:

方法1/2/3在开发环境、预发布环境都可以读取到jar包中的文件,方法4则只有开发环境中可以、直接从jar包读取失败。

3.1方法一

InputStream in = null;
ClassPathResource classPathResource = new ClassPathResource("templates/jumppage.html");
in = classPathResource.getInputStream();
StringBuffer buff = new StringBuffer();
byte[] filecontent = new byte[1024];
while((in.read(filecontent)) != -1){String strRead = new String(filecontent);buff.append(strRead);
}
byte[] bytes = buff.toString().getBytes();

注:使用classPathResource.getFile()会报错找不到该文件,原因是springboot打成了jar包,classPathResource.getFile()无法读取jar包目录下的文件

3.2方法二

InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("templates/jumppage.html");

3.3方法三

InputStream inputStream = this.getClass().getResourceAsStream("/templates/jumppage.html");

3.4方法四

File file = ResourceUtils.getFile("classpath:templates/jumppage.html");
InputStream inputStream = new FileInputStream(file);

SpringBoot打包后资源文件读取问题

springboot项目打包之后,将所有依赖都打入jar包,同时也将系统中要使用的一些资源文件也会打进来,之后运行这个jar包,里面包含的资源文件不能再像文件系统那样直接在classpath下就可以使用了。

如下所示,这段代码在idea中运行,可以按照预期,正确访问到资源文件hello.txt。

package com.xxx.springresourcedemo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.ClassPathResource;import java.io.File;
import java.io.InputStream;@SpringBootApplication
public class SpringresourcedemoApplication implements CommandLineRunner {public static void main(String[] args) {SpringApplication.run(SpringresourcedemoApplication.class, args);}@Overridepublic void run(String... args) throws Exception {try {String path = new ClassPathResource("hello.txt").getURL().getPath();File file = new File(path);System.out.println(file.getPath()+" exists -> "+file.exists());}catch (Exception e){System.out.println("exception -> "+e.getMessage());}}
}

在 idea中运行程序,打印信息如下:

img

但是如果我们打包,直接在windows下或者在linux下运行,这个代码的结果就发生了改变:

img

我们可以通过反编译工具看jar包的内容,hello.txt文件确实在BOOT-INF\classes目录下:

img

打包之后运行的结果为什么会出现这个问题?其实仔细想想,jar包内的文件路径发生了改变,当然就不能再像文件系统那样使用这个文件了。

那么问题来了,静态文件怎么加载,springboot又是如何加载application.yml或者其他配置文件的呢?其实它是通过读取流的方式来加载资源文件的。

有了这个思路,我们改变代码,通过InputStream流来读取文件,看看结果怎样?

package com.xxx.springresourcedemo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.ClassPathResource;import java.io.File;
import java.io.InputStream;@SpringBootApplication
public class SpringresourcedemoApplication implements CommandLineRunner {public static void main(String[] args) {SpringApplication.run(SpringresourcedemoApplication.class, args);}@Overridepublic void run(String... args) throws Exception {try{InputStream in = new ClassPathResource("hello.txt").getInputStream();byte[] data = new byte[1024];int len;String content = "";while((len=in.read(data))!=-1){content += new String(data,0,len);}in.close();System.out.println("file content -> "+content);}catch (Exception e){System.out.println("exception -> "+e.getMessage());}}
}

这个代码,无论实在idea中运行,还是打包之后运行,结果都一样:

img

打包之后运行:

img

这样,我们大概就知道了,通过流的方式可以读取resources资源文件。

如果你使用了流的方式读取资源文件,发现还是不能读取,那么问题就是打包的时候资源文件被过滤了,这个时候就需要考虑打包配置了。可以参考如下pom.xml:

<build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.yml</include><include>**/*.txt</include></includes><filtering>true</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>3.0.1</version><configuration><nonFilteredFileExtensions><nonFilteredFileExtension>txt,yml</nonFilteredFileExtension></nonFilteredFileExtensions></configuration></plugin></plugins>
</build>

我们可以看看springboot启动时加载application.properties的代码:

img

加载application.properties文件时用到了OriginTrackedPropertiesLoader类的load()方法,这个方法里面的内容如下:

img

断点的位置就开始通过reader读取了,而这里的CharacterReader内部类的构造器代码如下:

CharacterReader(Resource resource) throws IOException {this.reader = new LineNumberReader(new InputStreamReader(resource.getInputStream(), StandardCharsets.ISO_8859_1));
}

这里通过resource.getInputStream()流来封装InputStreamReader,最后封装为LineNumberReader,至此,springboot加载配置文件的思路也就是通过InputStream流来读取我们就清楚了。还有其他的配置文件的加载方法,比如spring.factories加载方法,其实也是通过InputStream流的方式来读取的。

springboot打包之后,资源文件不能直接通过路径的方式来作为文件使用,但是可以通过流的方式读取,这里配置文件,我们只需要知道内容,无需写出来,但是比如图片,我们需要在别的地方使用的,那么就需要通过InputStream,OutputStream流将资源文件读出来保存到一个可以访问的文件中,那么我们就可以正常使用了。

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

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

相关文章

java slot_LocalVariableTable之 Slot 复用

LocalVariableTable中的 Slot&#xff0c; 是存在复用现象的&#xff0c;这个我早就知道&#xff0c;但是&#xff0c;不太清楚是如何复用的。Java语言规范与JVM规范都没有对Java语言具体要如何使用JVM的局部变量slot做太多限制&#xff0c;只是规定了参数要从下标为0开始的局部…

关于使用this.getClass().getResource(“/“)获取文件时遇到的坑_ClassPathResource加载资源文件用法

最近在工作中遇到需要读取配置文件&#xff0c;然后第一想法就是将文件放到项目的resources目录下, 然后使用&#xff1a; String fileName "config/zh.md" String path this.getClass().getResource("/").getPath() fileName; System.out.println(p…

Objects.requireNonNull( )方法说明

Objects.requireNonNull( )方法在java.util.Objects中 作用就是判断一个对象是否为空 底层源码&#xff1a; /* param obj 需要检测是否为空的对象* param <T> 对象类型* return 对象不为空则返回该对象* throws 对象为空则报NullPointerException异常*/public static …

java 类的执行顺序_Java-类加载和main()方法的执行顺序?

2、类加载和main()的执行顺序&#xff1f;备注&#xff1a;执行main()方法会先加载main()方法所在的类。存在继承关系中&#xff0c;创建子类对象初始化过程为:父类静态成员和语句块子类静态成员和静态语句块父类普通成员和普通语句块父类构造函数子类普通成员和普通语句块父类…

利用Gson解析多层嵌套的JSON数据

数据实例: {"error": 0,"status": "success","results": [{"currentCity": "青岛","index"

编写一个程序实现方法的覆盖java_编写Java程序代码必须先声明一个____,然后在其中编写实现需求的业务代码。...

【多选题】下列关于多行注释的应用,正确的是( )【单选题】是在思维中把对象分解为各个部分、侧面、属性以及阶段,分别加以考察的方法。(1.0分)【判断题】多行注释“/*...*/”中不可以嵌套单行注释“//”。( )【多选题】直觉具有( )等特性。(2.0分)【多选题】马克思主义科学技术…

数据模型 同比 环比_同比和环比计算公式?

一、同比增长计算公式&#xff1a; 1、同比增长率(本期数&#xff0d;同期数)同期数100% 例子&#xff1a;比如说去年3月的产32313133353236313431303231363533e4b893e5b19e31333365666237值100万&#xff0c;本年3月的产值300万&#xff0c;同比增长率是多少&#xff1f; 本…

mysql80配置环境变量_MySQL:安装与配置

一、MySQL安装0、下载社区版安装包1、进入安装页面&#xff0c;这里不选择默认安装的所有工具&#xff0c;仅选择Server only。2、如果没有VC环境就点击execute安装&#xff0c;已安装就继续下一步。3、安装MySQL服务&#xff0c;Next。4、进入MySQL的配置环节&#xff0c;首先…

解决SVN无法add to ignore list的问题

有时候&#xff0c;在SVN中添加某文件夹到忽略列表即add to ignore list的时候报错&#xff0c;无法添加进忽略列表&#xff0c;这里总结一下&#xff0c;无非就是两个原因 仓库中已经存在了该文件夹的历史版本&#xff0c;因而无法忽略 解决方法&#xff1a;先备份该文件夹&am…

oracle正则表达式包含但不含_Oracle 正则表达式(详细)

Oracle 正则表达式正则表达式就是由普通字符(例如字符a到z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板&#xff0c;将某个字符模式与所搜索的字符串进行匹配。本文详细地列出了能在正则表达式中使用…

获取某个月中的第一天和最后一天某个月的天数当月第一天,当月最后一天,当年的第一天,当年的最后一天

获取某个月中的第一天和最后一天&某个月的天数 public static void main(String args[]){int month 2;// 2月Calendar cal Calendar.getInstance();cal.set(Calendar.YEAR, 2022);cal.set(Calendar.MONTH, month - 1);int max cal.getActualMaximum(Calendar.DATE);int…

python使用loaddata_Python中LOADDATAINFILE语句导入数据(txt)进入MySQL的一些注意事项...

问题&#xff1a;ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ROW 1 at line 1")代码如下&#xff1a;# -*- coding: utf-8 -*-"&quo…

SimpleDateFormat 日期格式化,以及sdf.parse(“2022-02-30“)顺序加问题

时间日期标识符&#xff1a; yyyy&#xff1a;年 MM&#xff1a;月 dd&#xff1a;日 hh&#xff1a;1~12小时制(1-12) HH&#xff1a;24小时制(0-23) mm&#xff1a;分 ss&#xff1a;秒 S&#xff1a;毫秒 E&#xff1a;星期几 D&#xff1a;一年中的第几…

SimpleDateFormat的线程不安全问题

一、前言 日期的转换与格式化在项目中应该是比较常用的了 一个问题&#xff1a;项目中的日期转换怎么用的&#xff1f;SimpleDateFormat 用过吗&#xff1f;能说一下 SimpleDateFormat 线程安全问题吗&#xff0c;以及如何解决&#xff1f; 回答&#xff1a;平时就是在全局定…

JVM——System.gc、内存溢出、内存泄漏、STW、安全点、安全区域、强软弱虚引用

文章目录①. System.gc()的理解②. 内存溢出(out of Memory)③. 内存泄漏(Memory Leak)④. Stop The World⑤. 多线程中的并行与并发⑥. 垃圾回收的并行、串行、并发⑦. 安全点(Safepoint)⑧. 安全区域(Safe Region)⑨. 引用①. 强引用:不回收②. 软引用: 内存不足即回收③. 弱…

大专生自学java找不到工作_自学Java真的找不到好工作吗?

自学Java真的找不到好工作吗&#xff1f;只能说有点难&#xff01;虽然职友集数据显示Java开发相关的岗位日招聘量为89754条&#xff0c;全国Java开发工程师的平均薪资为13210元/月。从以上可以看出目前Java行业还远没有饱和&#xff0c;Java开发人才在就业市场也是很吃香&…

Java——ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法

文章目录①. ThreadLocal简介①. ThreadLocal是什么②. api介绍③. 永远的helloword④. 通过上面代码总结②. 从阿里ThreadLocal规范开始①. 非线程安全的SimpleDateFormat②. 将SimpleDateFormat定义成局部变量(方案一)③. ThreadLocal 解决日期格式乱码问题④. 阿里规范怎么说…

java后端概述_Java后端测试概述

[本文出自天外归云的博客园]多种单测技术1. 要学会Spring MVC/Boot测试中自带的mock方法。2. 学会junit中的方法&#xff0c;对于注解的使用等。3. 学会使用结合第三方Mockito来做mock测试。一些技巧和概念1. 对于复杂方法中&#xff0c;要学会如何拆解逻辑&#xff0c;划分单元…

Java私有方法运用场景_java6-3 封装和private关键字

1、 private:是一个权限修饰符可以修饰成员变量和成员方法被其修饰的成员只能在本类中被访问定义一个学生类&#xff1a;成员变量&#xff1a;name&#xff0c;age成员方法&#xff1a;show()方法2、我们在使用这个案例的过程中&#xff0c;发现了一个问题&#xff1a;通过对象…

JPA入门

文章目录JPA概述JPASpring Data JPAJPA注解基础注解EntityTableIdEnumeratedTransientColumnTemporal联合主键注解IdClassEmbeddable和EmbeddedId注解实体之间关联关系注解OneToOneManyToOne和OneToManyRepositoryJPA查询方式DQM&#xff08;定义查询方法&#xff09;使用实例D…