spring-boot - Heroku SpringBoot ClassPathResource 获取 FileNotFoundException

标签 spring-boot heroku resources classpath filenotfoundexception

我在 Heroku 上部署了一个 SpringBoot 项目,尽管它在本地运行得很好,但我得到了 FileNotFoundException。

这是代码:

@GetMapping(path = "/api/items/image/get/{file_name}")
public ResponseEntity<InputStreamResource> getItemImage(@PathVariable("file_name") String fileName) {
    // append "_thumbsnail" to file name
    fileName = fileName.split("\\.")[0] + "_thumbsnail." + fileName.split("\\.")[1];
    ClassPathResource imgFile = new ClassPathResource("item_image/" + fileName, getClass().getClassLoader());
    try {
        return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG)
                .body(new InputStreamResource(imgFile.getInputStream()));
    } catch (IOException e) {
        e.printStackTrace();
        return ResponseEntity.badRequest().body(null);
    }
}

这是错误:

2019-01-21T14:29:15.221959+00:00 app[web.1]: java.io.FileNotFoundException: class path resource [item_image/1234567890128_thumbsnail.png] cannot be opened because it does not exist
2019-01-21T14:29:15.226272+00:00 app[web.1]: at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:180)
2019-01-21T14:29:15.226412+00:00 app[web.1]: at com.smartscan.api.controller.ItemAPIController.getItemImage(ItemAPIController.java:116)
2019-01-21T14:29:15.226419+00:00 app[web.1]: at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2019-01-21T14:29:15.226447+00:00 app[web.1]: at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
2019-01-21T14:29:15.226474+00:00 app[web.1]: at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2019-01-21T14:29:15.226502+00:00 app[web.1]: at java.lang.reflect.Method.invoke(Method.java:498)
2019-01-21T14:29:15.226531+00:00 app[web.1]: at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
2019-01-21T14:29:15.226557+00:00 app[web.1]: at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
2019-01-21T14:29:15.226594+00:00 app[web.1]: at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
2019-01-21T14:29:15.226621+00:00 app[web.1]: at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
2019-01-21T14:29:15.226648+00:00 app[web.1]: at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
2019-01-21T14:29:15.226674+00:00 app[web.1]: at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
2019-01-21T14:29:15.226699+00:00 app[web.1]: at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
2019-01-21T14:29:15.226755+00:00 app[web.1]: at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
2019-01-21T14:29:15.226816+00:00 app[web.1]: at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
2019-01-21T14:29:15.226822+00:00 app[web.1]: at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
2019-01-21T14:29:15.226853+00:00 app[web.1]: at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
2019-01-21T14:29:15.226882+00:00 app[web.1]: at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
2019-01-21T14:29:15.226884+00:00 app[web.1]: at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
2019-01-21T14:29:15.226891+00:00 app[web.1]: at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
2019-01-21T14:29:15.226919+00:00 app[web.1]: at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2019-01-21T14:29:15.226941+00:00 app[web.1]: at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
2019-01-21T14:29:15.226970+00:00 app[web.1]: at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
2019-01-21T14:29:15.226999+00:00 app[web.1]: at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2019-01-21T14:29:15.227006+00:00 app[web.1]: at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
2019-01-21T14:29:15.227045+00:00 app[web.1]: at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
2019-01-21T14:29:15.227058+00:00 app[web.1]: at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
2019-01-21T14:29:15.227059+00:00 app[web.1]: at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
2019-01-21T14:29:15.227084+00:00 app[web.1]: at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)

我之前搜索过是否有人遇到过这个问题,但找不到解决的解决方案。

这是heroku上的目录结构:

~/target $ ls
classes         mvn-dependency-list.log
generated-sources   smart-scan-0.0.1-SNAPSHOT.jar
generated-test-sources  smart-scan-0.0.1-SNAPSHOT.jar.original
maven-archiver      test-classes
maven-status

这是我创建文件时的日志:

===== itemImageFolder: file:/app/target/smart-scan-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/item_image/1133113.png
2019-01-22T14:47:00.507783+00:00 app[web.1]: ====== Thumps nail created file:/app/target/smart-scan-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/item_image/1133113_thumbsnail.png

这是我加载文件时的日志:

2019-01-22T14:48:04.287928+00:00 app[web.1]: ====== READING RESOURCE file:/app/target/smart-scan-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/item_image/1133113_thumbsnail.png
2019-01-22T14:48:04.291731+00:00 app[web.1]: java.lang.IllegalArgumentException: InputStream must not be null

如何保存文件:

    URL itemImageFolder = getClass().getClassLoader().getResource("item_image/");
    System.out.println("===== itemImageFolder: " + itemImageFolder.getPath() + imagePath);
    Path rootLocation = Paths.get(itemImageFolder.getPath());
    if (Files.notExists(rootLocation)) {
        Files.createDirectories(rootLocation);
    }
    Files.copy(file.getInputStream(), Paths.get(itemImageFolder.getPath() + imagePath),
            StandardCopyOption.REPLACE_EXISTING);
    // create thumbs nail
    BufferedImage originalImage = ImageIO.read(new File(itemImageFolder.getPath() + imagePath));
    int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
    BufferedImage resizeImageJpg = resizeImage(originalImage, type);
    System.out.println(
            "====== Thumps nail created " + itemImageFolder.getPath() + barcode + "_thumbsnail." + extension);

    ImageIO.write(resizeImageJpg, extension,
            new File(itemImageFolder.getPath() + barcode + "_thumbsnail." + extension));

以及如何加载文件:

fileName = fileName.split("\\.")[0] + "_thumbsnail." + fileName.split("\\.")[1];
System.out.println("====== READING RESOURCE " + getClass().getClassLoader().getResource("item_image/").getPath() + fileName);
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("item_image/" + fileName);

更新: 我已经通过更改为使用Blob来存储Image来解决这个问题,但是不推荐这种解决方案。所以我仍然需要有在 Heroku 上部署 Spring Boot 应用程序经验的人来帮助我。

最佳答案

虽然我不太清楚为什么在 Heroku 上部署的 Spring 应用程序中无法获取文件路径,但我采用了另一种方法,这可能对其他遇到相同问题的人有所帮助。我利用了 Spring 的 Resource 方法,创建一个配置类并通过 @Value 注释将文件内容注入(inject)到变量中。我已经通过读取文件的 Bean 方法公开了文件内容的 String 值:

@Configuration
public class ResourceFiles {

    @Value("classpath:myfile.ext")
    private Resource myfile;

    @Bean(name = "myfile")
    public String myfile() {
        try (InputStream is = myfile.getInputStream()) {
            return StreamUtils.copyToString(is, Charset.forName("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}

然后,我通过 @Autowired 注释使用了文件字符串内容:

@Autowired
@Qualifier("myfile")
public String myfile;

关于spring-boot - Heroku SpringBoot ClassPathResource 获取 FileNotFoundException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54292481/

相关文章:

ruby-on-rails - 在 Heroku 上部署 Sidekiq Pro

Spring Boot Kubernetes 服务发现

java - 在 ControllerAdvice 之前捕获反序列化异常

ruby-on-rails - 如何销毁包括:dependent records in other tables的表的所有记录

java - 相当于 Jar 中的 this.getClass().getClassLoader().getResource (".").toURI()

java - 为什么将项目布局资源与Java源代码分开?

Maven 在多模块项目中复制资源

spring - 在请求头验证错误的情况下,让 Spring 响应 400(而不是 500)

spring-boot - 自升级到 spring boot v2 以来,h2Database 上的 flyway 迁移出错

node.js - 在 Heroku 上运行 Node.js 应用程序时出错