文章目录
前言
因为在idea编辑器上和被tomcat实际部署中,资源文件的路径实际是不同的,所以常常使用getResource来动态获取资源文件的真实地址,TestJsoup.class.getClassLoader().getResource("SimpleTest.xml").getPath()
,例如此
然而有时却发现获取到的是空值,这是为什么呢?
解决
如图所示,应该将资源文件xml放置在src/java路径下,然后java目录设置为source root,创建资源文件夹resource,将xml放进去这样才能识别到
为什么会有这样的放置xml的规则呢?
因为xml文件在idea中读写和部署到tomcat时遵循了两种文件放置规则,也就是各自规定了一套文件路径规则,路径发生了变化,如果不这样设置,部署时就会发现找不到这个文件
resource路径也需要定义
为什么需要将java目录变成source root类型才能识别到下面的xml文件呢?
.class 是获取当前类的 class 对象,getClassLoader()是获取当前的类加载器
类加载器可以将class文件加载到内存中,并创建一个类对象,getResource是用来获取类的资源的
而获取资源的默认路径就是类所在的路径,即是classPath,将src变成souce root文件类型,就当作类的开始路径了
因为每个类是不同的,虽然存在父子关系,然而并没有什么用,“子知道父,父不知道子”,不同的类加载器是无法相互访问的,这里使用当前类的加载器加载资源文件也是保证他们被同一个类加载器加载,这样 当前类就能够访问同样被同一个类加载器加载的资源文件了
为什么idea上放好的路径,被tomcat部署之后路径就变了呢?
这是因为idea和tomcat对于工程文件的管理方式不同 ,各自制定了一套文件放置规则
最初,由Maven构建的web工程,主代码放在src/main/java路径下,资源放在src/main/resources路径下
然后
JavaWeb项目部署服务器时会将项目打包成Jar包或者war包,此时就不会存在 src/main/resources,也没有java 目录,JVM会在编译项目时,主动将 java文件编译成 class文件 并将与 resources 下的静态文件一并放在 target/classes目录下;
如图,java文件都编译成了class文件,资源文件都被复制了一份一并放到了target/classes目录,使用的是tomcat文件放置规则
有趣的是,在idea上,本地运行时
Java文件编译成 class文件被JVM执行,当前项目即为Java进程的工作空间,虽然class文件在target/classes目录下,但是target/classes不是class文件运行的目录,只是存放的目录,运行目录还是在IDEA的模块下,所以运行时会找到 src/main/resources 资源文件。 使用的是本地文件放置规则
类与它的类加载器都可以加载资源文件,区别是什么?
class.getClassLoader().getResourceAsStream() 和 class.getResouceAsStream() 的区别
a)class.getClassLoader().getResourceAsStream(String name) 默认从classpath中找文件(文件放在resources目录下),name不能带"/“,否则会抛空指针。采用相对路径, “/“就相当于当前进程的根目录,即项目根目录;
inStream = PropertiesTest.class.getClassLoader().getResourceAsStream(“com/test/demo/test.properties”);
意思是从src下找文件
b)class.getResourceAsStream(String name) 是采用绝对路径,绝对路径是相对于 classpath 根目录的路径,”/” 就代表着 classpath,所以 name 属性需要前面加上 “/”;
inStream = PropertiesTest.class.getResourceAsStream(”/com/test/demo/test.properties")
意思是从项目根路径开始找文件
spring注解加载配置文件
写资源文件加载代码那是很久以前了,现在都是注解,@一下自动配置
如果工程中使用Spring,可以通过注解的方式获取配置信息,但需要将配置文件放到Spring配置文件中扫描后,才能将配置信息放入上下文。
<context:component-scan base-package="com.xxxx.service"/>
<context:property-placeholder location="classpath:properties/xxx.properties" ignore-unresolvable="true"/>
然后在程序中可以使用 @Value进行获取properties文件中的属性值,如下:
@Value("${xxxt.server}")
private static String serverUrl;
采用Spring配置
也可以在Spring配置文件中读取属性值,赋予类成员变量
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:properties/xxx.properties"/>
</bean>
<bean id="service" class="com.xxxx.service.ServiceImpl"> <property name="serverUrl" value="${xxxt.server}" />
</bean>
</beans>
SpringBoot项目启动后,动态的读取类路径下文件数据
InputStream inputStream = EncryptUtil.class.getResourceAsStream("/HelloServiceEncryptFile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line = reader.readLine();
// 获取类路径下的文件路径
File path = new File(ResourceUtils.getURL("classpath:").getPath());
if (!path.exists()) {
path = new File("");
}
log.info("path = {}", path.getAbsolutePath());
File upload = new File(path.getAbsolutePath(), "com/study/service");
if (!upload.exists()) {
upload.mkdirs();
}
FileOutputStream fos = new FileOutputStream(upload.getAbsolutePath() + File.separator + "hello.txt");
IoUtil.copy(inputStream, fos);
fos.close();
inputStream.close();