https://cloud.tencent.com/developer/article/2193203
項目場景:
在Springboot中利用Resource來獲取文件并在前端返回該文件, 本地測試正常, 打包到遠程報錯: cannot be resolved to absolute file path because it does not reside in the file system
問題描述:
緊接上一個問題: 項目打包成 jar 后包無法讀取src/main/resources下文件, 在Springboot打包之后, 無法讀取到jar包內的文件, 因此采取Resource來獲取jar內相對路徑地址的文件. 只有一個需要下載文件的時候沒有問題, 然后在指定文件夾下新增一個文件后本地下載正常, 打包后下載出現(xiàn)問題: 下載該文件時, 后端拋出異常, 異常如下
class path resource [static/xxx模板.xlsx] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/mis-project-java-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/static/%e5%b7%a5%e8%b5%84%e8%a1%a8%e6%a8%a1%e6%9d%bf.xlsx
復制
原因分析:
需要下載文件存放的地址:
修改前代碼:
@Override
@SneakyThrows(IOException.class)
public HttpServletResponse downloadFile(HttpServletRequest request, HttpServletResponse response) {
//設置文件路徑
org.springframework.core.io.Resource resource = new ClassPathResource("static/" + "xxx模板.xlsx");
if (resource.exists()) {
//異常在下一行拋出
File file = resource.getFile();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/vnd.ms-excel");
String fileName = resource.getURI().toString().substring(resource.getURI().toString().lastIndexOf("/") + 1);
response.setHeader("content-disposition", "attachment;filename=" + fileName);
response.flushBuffer();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
if (bis != null) {
bis.close();
}
return response;
}
return null;
}
復制
對問題部分本地斷點調試
本地斷點調試:
- 可以看到, 調用的是 AbstractFileResolvingResource下的getFIle 方法. 然后該方法會調用 ResourceUtils下的getFile() 方法
- 可以看到在ResourceUtils下的getFile() 方法中, 因為 resourceUrl.getProtocol() 為File, 說明該url 地址對應的資源是文件, 所以直接返回這個文件
- 后續(xù)源碼如何返回這個文件可以自己繼續(xù)深入
對問題部分遠程斷點調試:
- 依舊是進入 resource.getFile(); 的方法內. 因為當前 url的protocol 屬性時 jar, 不是vfs, 依舊走的是ResourceUtils下的getFile() 方法
- 在ResourceUtils下的getFile() 方法中, 因為 resourceUrl.getProtocol() 為jar, 因此會拋出異常
- 異常拋出后被全局捕獲, 然后在前端顯示
解決方案:
通過上面的調試我們可以看到, org.springframework.core.io.Resource 這個類的getFile()方法, 會自動獲取構建resource對象帶參構造中的url, 然后根據這個url確定該文件的類型. 因為在本地時調試時, 通過resource.getFile()獲取的url類型的 protocol 屬性為File, 所以可以自動生成文件; 然而在將項目打包成jar部署在服務器上時, 因為該文件是在jar里面的. 因此通過resource.getFile()獲取的url類型的 protocol 屬性為jar. 所以拋出該異常
cannot be resolved to absolute file path because it does not reside in the file system: 文件url
.
因此, 方法有兩種: 一種是直接將該文件放入服務器其他目錄下而不是在jar包中. 另一種就是通過流來獲取jar里面的文件. 而本人采取第二種方式, 通過輸入流來讀取jar內的文件, 然后通過輸出流將其輸出.文章來源:http://www.zghlxwxcb.cn/news/detail-417311.html
修改后的代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-417311.html
@Override
@SneakyThrows(IOException.class)
public HttpServletResponse downloadFile(HttpServletRequest request, HttpServletResponse response) {
//設置文件路徑
org.springframework.core.io.Resource resource = new ClassPathResource("static/" + "xxx模板.xlsx");
if (resource.exists()) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/vnd.ms-excel");
String fileName = resource.getURI().toString().substring(resource.getURI().toString().lastIndexOf("/") + 1);
response.setHeader("content-disposition", "attachment;filename=" + fileName);
response.flushBuffer();
//放棄使用直接獲取文件的方式, 改成使用流的方式
BufferedInputStream bis = new BufferedInputStream(resource.getInputStream());
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
if (bis != null) {
bis.close();
}
return response;
}
return null;
}
到了這里,關于cannot be resolved to absolute file path because it does not reside in the file system 問題解決的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!