springboot打包后资源文件读取问题
Posted luffy5459
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
@Override
public 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中运行程序,打印信息如下:
但是如果我们打包,直接在windows下或者在linux下运行,这个代码的结果就发生了改变:
我们可以通过反编译工具看jar包的内容,hello.txt文件确实在BOOT-INF\\classes目录下:
打包之后运行的结果为什么会出现这个问题?其实仔细想想,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);
@Override
public 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中运行,还是打包之后运行,结果都一样:
打包之后运行:
这样,我们大概就知道了,通过流的方式可以读取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的代码:
加载application.properties文件时用到了OriginTrackedPropertiesLoader类的load()方法,这个方法里面的内容如下:
断点的位置就开始通过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流将资源文件读出来保存到一个可以访问的文件中,那么我们就可以正常使用了。
以上是关于springboot打包后资源文件读取问题的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot 项目打包后获取不到resource下资源的解决
Spring Boot参考教程Spring Boot Jar方式读取资源文件
springboot打包后静态资源webapp文件夹无法打包进去