使用可执行Jar时找不到Spring-Boot资源
我再次遇到一个奇怪的问题,希望有人可以提供帮助。
我有一个spring boot后端模块,在eclipse中运行良好,在application.java中启动main时应用程序是可执行的。 一切都很好。
我的应用程序使用csv-files将示例数据导入数据库,这些文件包含在src / main / resources文件夹中。 如上所述,在eclipse中启动时一切正常。
现在我想将它作为可执行jar执行,应用程序开始启动然后无法启动,因为它无法找到csv文件。 它打印出来的路径,它查找文件的位置是正确的,csv文件包含在jar中。
该模块的Pom如下所示:
4.0.0 at.company.bbsng bbsng-import 0.1.0-SNAPSHOT bbsng-import-backend bbsng-import-backend at.company.bbsng.dataimport.Application org.springframework.boot spring-boot-starter-batch spring-boot-starter-logging org.springframework.boot org.springframework.boot spring-boot-starter-log4j org.springframework.boot spring-boot-starter-test test ... org.springframework.boot spring-boot-maven-plugin repackage
csv文件的路径在propery文件中配置如下:
# EXAMPLE PATH csv.path=config/csv/
java配置文件的部分如下:
... @Value("${csv.path}") private String csvExamplePath; @Bean public Resource addressResource() { return new ClassPathResource(csvExamplePath + CSV_ADDRESS); } ...
在jar中,文件位于路径中
\config\csv\
堆栈跟踪:
Caused by: java.io.FileNotFoundException: class path resource [config/csv/Company.csv] cannot be resolved to absolute file path because it does not reside in th e file system: jar:file:/C:/Development/Projekte/bbsng/trunk/import/backend/target/bbsng-import-backend-0.1.0-SNAPSHOT.jar!/config/csv/Company.csv at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:207) at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52) at at.compax.bbsng.dataimport.app.source.company.CompanyGenerator.init(CompanyGenerator.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java
同样,应用程序在从eclipse启动时按预期工作,只有可执行jar抱怨缺少csv文件,jar中已有的内容。
任何线索都会很棒。
好的,我已经找到了真正的问题和解决方案。
首先,应用程序使用正确的csv文件路径,但是在使用我在以下链接中找到的可执行jar时还有另一个问题。 计算器,链接
在我开始使用可执行jar之前,我使用以下解决方案来获取CSV文件(问题是getFile()):
final List resourceLines = FileReadUtils.readLines(specialisationResource.getFile()); for (final String line : resourceLines) { data.add(getNewTransientSpecialisation(line)); }
但是在可执行的jar中我无法将我的资源用作文件,我需要将其用作流,请参阅上面提供的链接。 所以我需要改变我的代码。 如果您更喜欢使用本机java,则可以执行以下操作:
final InputStream inputStream = specialisationResource.getInputStream(); final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = bufferedReader.readLine()) != null) { data.add(getNewTransientSpecialisation(line)); }
我更喜欢使用框架并使用如下的apache commons:
final List resourceLines = IOUtils.readLines(specialisationResource.getInputStream()); for (final String line : resourceLines) { data.add(getNewTransientSpecialisation(line)); }
所以请记住,不要使用File()获取资源,总是使用流从开始时避免该问题:-)
希望能帮助别人。
我也遇到了这个限制,并创建了这个库来克服这个问题: spring-boot-jar-resources
它基本上允许您使用Spring Boot注册自定义ResourceLoader,根据需要从JAR中提取类路径资源,透明地:
new SpringApplicationBuilder() .sources(Application.class) .resourceLoader(new JarResourceLoader()) .run(args);
使用该ResourceLoader,您可以在任何类路径资源上执行resource.getFile()
。
现在我需要从JAR中找到xmlFiles到资源文件夹中,并且已经面临类似的问题。 我想分享我的发现以及我是如何工作的,也许它很有帮助。
在一个jar中,我在src / main / resources下有“db-input”文件夹,其中包含用于DB-Input的xml-Files的任何数字。 我的应用程序是基于Spring的:
@Component public class DatabaseInitializer implements InitializingBean { @Autowired DomainConfigurationRepository repository; @Autowired MarshallerService marshallerService; @Autowired ApplicationContext context; @Override public void afterPropertiesSet() throws Exception { final Resource[] resources = context.getResources("classpath*:db-input/*"); final Set filePaths = findInputFileNames(resources); final Set configurations = createConfigurations(filePaths); repository.save(configurations); } private Set createConfigurations(final Set filePaths) throws Exception { final Set configurations = new HashSet<>(); for(final String path : filePaths){ final Resource resource = context.getResource(path); final DomainConfigurationXO xoConfiguration = marshallerService.unmarshal(resource.getInputStream()); final DomainConfiguration configuration = PopulationUtils.getPopulatedConfiguration(xoConfiguration); configurations.add(configuration); } return configurations; } public Set findInputFileNames(final Resource[] inputDirectoryResources) throws IOException { return Arrays.stream(inputDirectoryResources) .map(resource -> extractURI(resource)) .collect(Collectors.toSet()); } private String extractURI(Resource resource){ try { return resource.getURI().toString(); } catch (IOException e) { throw new RuntimeException(e); } } }