运行jar时找不到类路径资源

gyo*_*der 106 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并验证它在顶层包含文件"message.txt"(与application.properties相同的级别).

这是应用程序:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application implements CommandLineRunner {

    private static final Logger logger = Logger.getLogger(Application.class);

    @Value("${message.file}")
    private Resource messageResource;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... arg0) throws Exception {
        // both of these work when running as Spring boot app from STS, but
        // fail after mvn package, and then running as java -jar
        testResource(new ClassPathResource("message.txt"));
        testResource(this.messageResource);
    }

    private void testResource(Resource resource) {
        try {
            resource.getFile();
            logger.debug("Found the resource " + resource.getFilename());
        } catch (IOException ex) {
            logger.error(ex.toString());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

例外:

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
Run Code Online (Sandbox Code Playgroud)

And*_*son 163

resource.getFile()期望资源本身在文件系统上可用,即它不能嵌套在jar文件中.这就是为什么它在您运行STS中的应用程序时有效,但是一旦您构建了应用程序并从可执行jar运行它就无法工作.而不是使用getFile()访问资源的内容,我推荐使用getInputStream()来代替.这将允许您阅读资源的内容,无论它位于何处.

  • 在我的情况下,我需要提供密钥库文件的路径(为了tomcat https连接器).我想将jks文件包装在我的jar中.根据上述解决方案,这是不可能的.你熟悉其他方法吗? (5认同)

anu*_*ava 48

如果你使用Spring框架,然后读ClassPathResourceString使用是非常简单的Spring框架的FileCopyUtils:

String data = "";
ClassPathResource cpr = new ClassPathResource("static/file.txt");
try {
    byte[] bdata = FileCopyUtils.copyToByteArray(cpr.getInputStream());
    data = new String(bdata, StandardCharsets.UTF_8);
} catch (IOException e) {
    LOG.warn("IOException", e);
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是Spring用户的最佳解决方案.对我来说很棒. (4认同)
  • 不适用于 jar,可以从 IDE 获取数据 (3认同)

小智 37

如果要使用文件:

ClassPathResource classPathResource = new ClassPathResource("static/something.txt");

InputStream inputStream = classPathResource.getInputStream();
File somethingFile = File.createTempFile("test", ".txt");
try {
    FileUtils.copyInputStreamToFile(inputStream, somethingFile);
} finally {
    IOUtils.closeQuietly(inputStream);
}
Run Code Online (Sandbox Code Playgroud)

  • 对于任何需要这个的人。如果 FileUtils.copyInputStreamToFile 不可解析。您可能需要添加“commons-io”作为依赖项。 (2认同)

zhu*_*wei 6

当spring boot项目作为jar运行并且需要在classpath中读取一些文件时,我通过下面的代码实现它

Resource resource = new ClassPathResource("data.sql");
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
reader.lines().forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)


小智 5

要从文件夹中获取数据列表src/main/resources/data:首先在属性文件中将文件夹位置指定为 resourceLoader.file.location=data.

然后在类中声明你的位置:

@Value("${resourceLoader.file.location}")
@Setter
private String location;

private final ResourceLoader resourceLoader;

public void readallfilesfromresources() {
       Resource[] resources;

        try {
            resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources("classpath:" + location + "/*.json");
            for (int i = 0; i < resources.length; i++) {
                try {
                InputStream is = resources[i].getInputStream();
                byte[] encoded = IOUtils.toByteArray(is);
                String content = new String(encoded, Charset.forName("UTF-8"));
                }
            }
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
}
Run Code Online (Sandbox Code Playgroud)