spring-boot - Heroku SpringBoot ClassPathResource 获取 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 应用程序中获取文件路径,但我已经找到了另一种方法,它可能对遇到相同问题的其他人有所帮助。@Value
我通过创建配置类并通过注释将文件内容注入变量来利用 Spring 的资源方法。我通过读取文件的 Bean 方法公开了文件内容的字符串值:
@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;
推荐阅读
- django - 电子邮件正文显示 html 代码代替 django 中的模板
- python - 函数值存储在 python.how 上的 int 中?
- .net - 在 .NET Windows 应用程序中使用 Windows 凭据登录
- mips - MIPS FPU 编程 - 操作数类型不正确
- python - 字典列表
- git - Git:如何删除已删除的忽略文件?
- java - Java中的Android Studio Code接受用户输入和显示输出
- javascript - setTimeout() 倒计时不工作 Discord JS
- php - 无法修改主机上的标头信息错误
- powershell - 在一行中交换字符串顺序或在powershell中交换行顺序