IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot读取resource或template中的文件 -> 正文阅读

[Java知识库]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);
    }
 
    @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中运行程序,打印信息如下:

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);
    }
 
    @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中运行,还是打包之后运行,结果都一样:

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流将资源文件读出来保存到一个可以访问的文件中,那么我们就可以正常使用了。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-08 18:52:54  更:2022-06-08 18:53:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:39:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码