Java 作为jar运行时未找到类路径资源
在Spring Boot 1.1.5和1.1.6中都存在这个问题-我正在使用@Value注释加载一个类路径资源,当我从STS(3.6.0,Windows)中运行应用程序时,它工作得很好。但是,当我运行一个mvn包,然后尝试运行jar时,会出现FileNotFound异常 资源message.txt位于src/main/resources中。我已经检查了jar,并验证它在顶层(与application.properties相同的级别)包含文件“message.txt” 以下是应用程序:Java 作为jar运行时未找到类路径资源,java,spring-boot,Java,Spring Boot,在Spring Boot 1.1.5和1.1.6中都存在这个问题-我正在使用@Value注释加载一个类路径资源,当我从STS(3.6.0,Windows)中运行应用程序时,它工作得很好。但是,当我运行一个mvn包,然后尝试运行jar时,会出现FileNotFound异常 资源message.txt位于src/main/resources中。我已经检查了jar,并验证它在顶层(与application.properties相同的级别)包含文件“message.txt” 以下是应用程序: @配置 @
@配置
@组件扫描
@启用自动配置
公共类应用程序实现CommandLineRunner{
私有静态最终记录器=Logger.getLogger(Application.class);
@值(“${message.file}”)
私有资源;
公共静态void main(字符串[]args){
SpringApplication.run(Application.class,args);
}
@凌驾
公共无效运行(字符串…arg0)引发异常{
//当从STS作为Spring boot应用程序运行时,这两种方法都可以工作,但是
//mvn包后失败,然后作为java-jar运行
testResource(新类路径资源(“message.txt”);
testResource(this.messageResource);
}
私有void testResource(资源){
试一试{
resource.getFile();
debug(“找到资源”+resource.getFilename());
}捕获(IOEX异常){
logger.error(例如toString());
}
}
}
例外情况:
c:\Users\glyoder\Documents\workspace-sts-3.5.1.RELEASE\classpath-resource-proble
m\target>java -jar demo-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.1.5.RELEASE)
2014-09-16 08:46:34.635 INFO 5976 --- [ main] demo.Application
: Starting Application on 8W59XV1 with PID 5976 (C:\Users\glyo
der\Documents\workspace-sts-3.5.1.RELEASE\classpath-resource-problem\target\demo
-0.0.1-SNAPSHOT.jar started by glyoder in c:\Users\glyoder\Documents\workspace-s
ts-3.5.1.RELEASE\classpath-resource-problem\target)
2014-09-16 08:46:34.640 DEBUG 5976 --- [ main] demo.Application
: Running with Spring Boot v1.1.5.RELEASE, Spring v4.0.6.RELEA
SE
2014-09-16 08:46:34.681 INFO 5976 --- [ main] s.c.a.AnnotationConfigA
pplicationContext : Refreshing org.springframework.context.annotation.Annotation
ConfigApplicationContext@1c77b086: startup date [Tue Sep 16 08:46:34 EDT 2014];
root of context hierarchy
2014-09-16 08:46:35.196 INFO 5976 --- [ main] o.s.j.e.a.AnnotationMBe
anExporter : Registering beans for JMX exposure on startup
2014-09-16 08:46:35.210 ERROR 5976 --- [ main] demo.Application
: java.io.FileNotFoundException: class path resource [message.
txt] cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/C:/Users/glyoder/Documents/workspace-sts-3.5.1.RELEASE/cl
asspath-resource-problem/target/demo-0.0.1-SNAPSHOT.jar!/message.txt
2014-09-16 08:46:35.211 ERROR 5976 --- [ main] demo.Application
: java.io.FileNotFoundException: class path resource [message.
txt] cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/C:/Users/glyoder/Documents/workspace-sts-3.5.1.RELEASE/cl
asspath-resource-problem/target/demo-0.0.1-SNAPSHOT.jar!/message.txt
2014-09-16 08:46:35.215 INFO 5976 --- [ main] demo.Application
: Started Application in 0.965 seconds (JVM running for 1.435)
2014-09-16 08:46:35.217 INFO 5976 --- [ Thread-2] s.c.a.AnnotationConfigA
pplicationContext : Closing org.springframework.context.annotation.AnnotationCon
figApplicationContext@1c77b086: startup date [Tue Sep 16 08:46:34 EDT 2014]; roo
t of context hierarchy
2014-09-16 08:46:35.218 INFO 5976 --- [ Thread-2] o.s.j.e.a.AnnotationMBe
anExporter : Unregistering JMX-exposed beans on shutdown
期望资源本身在文件系统上可用,即不能嵌套在jar文件中。这就是为什么在STS中运行应用程序时它可以工作,但在构建应用程序并从可执行jar运行应用程序后就不工作了。与其使用
getFile()
来访问资源的内容,我建议使用。这将允许您读取资源的内容,而不管它位于何处。如果要使用文件:
ClassPathResource ClassPathResource=newclassPathResource(“static/something.txt”);
InputStream InputStream=classPathResource.getInputStream();
File somethingFile=File.createTempFile(“test”,“.txt”);
试一试{
copyInputStreamToFile(inputStream,somethingFile);
}最后{
IOUtils.close安静(inputStream);
}
如果您使用的是Spring框架,那么将ClassPathResource
读入字符串
非常简单:
字符串数据=”;
ClassPathResource cpr=新的ClassPathResource(“static/file.txt”);
试一试{
byte[]bdata=FileCopyUtils.copyToByteArray(cpr.getInputStream());
数据=新字符串(bdata,StandardCharsets.UTF_8);
}捕获(IOE异常){
日志警告(“IOException”,e);
}
我也遇到了这个限制,创建了这个库来克服这个问题:
它基本上允许您向Spring Boot注册一个定制的ResourceLoader,它可以根据需要透明地从JAR中提取类路径资源。当Spring Boot项目作为JAR运行并且需要读取类路径中的一些文件时,我通过以下代码实现它
Resource resource = new ClassPathResource("data.sql");
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
reader.lines().forEach(System.out::println);
球衣需要拆开包装
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>com.myapp</groupId>
<artifactId>rest-api</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build>
org.springframework.boot
springbootmaven插件
com.myapp
RESTAPI
我以java 8的方式创建了一个ClassPathResourceReader类,以便从classpath轻松读取文件
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import org.springframework.core.io.ClassPathResource;
public final class ClassPathResourceReader {
private final String path;
private String content;
public ClassPathResourceReader(String path) {
this.path = path;
}
public String getContent() {
if (content == null) {
try {
ClassPathResource resource = new ClassPathResource(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
content = reader.lines().collect(Collectors.joining("\n"));
reader.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
return content;
}
}
利用率:
String content = new ClassPathResourceReader("data.sql").getContent();
从src/main/resources/data文件夹获取数据列表--
首先,在属性文件中提到您的文件夹位置为-
resourceLoader.file.location=数据
在类内声明您的位置。
@值(${resourceLoader.file.location}”)
@塞特
私有字符串位置;
私有最终资源加载器资源加载器;
public void readallfilesfromresources(){
资源[]资源;
试一试{
resources=ResourcePatternUtils.getResourcePatternResolver(resourceLoader.getResources(“类路径:“+location+”/*.json”);
for(int i=0;i
基于Andy的,我使用以下方法来获取参考资料中目录和子目录下所有YAML的输入流(请注意,传递的路径不是以/
开头):
私有静态流getInputStreamsFromClasspath(
字符串路径,
路径匹配源模式解析程序解析程序
) {
试一试{
返回Arrays.stream(resolver.getResources(“/”+path+“/***.yaml”))
.filter(资源::存在)
.map(资源->{
试一试{
返回resource.getInputStream();
}捕获(IOE异常){
返回null;
}
})
.filter(对象::非空);
}捕获(IOE异常){
错误(“未能从目录{}获取定义”,路径e);
返回流。of();
}
}
关于最初的错误消息
无法解析为绝对文件路径,因为它不位于
文件系统
以下代码可能有助于找到路径问题的解决方案:
Paths.get("message.txt").toAbsolutePath().toString();
这样,您就可以确定应用程序希望丢失文件的位置。您可以在应用程序的主方法中执行此操作。我注意到的另一个重要问题是,在运行应用程序时,它会忽略文件/文件夹中的大写字母
in spring boot :
1) if your file is ouside jar you can use :
@Autowired
private ResourceLoader resourceLoader;
**.resource(resourceLoader.getResource("file:/path_to_your_file"))**
2) if your file is inside resources of jar you can `enter code here`use :
**.resource(new ClassPathResource("file_name"))**
Paths.get("message.txt").toAbsolutePath().toString();
@Autowired
ApplicationContext appContext;
// this will work when running the application, but will fail when running as jar
appContext.getResource("classpath:testfolder/message.txt");
appContext.getResource("classpath:Testfolder/message.txt");