cannot be resolved to absolute file path because it does not reside in the file system 问题解决
项目场景:
在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内相对路径地址的文件. 只有一个需要下载文件的时候没有问题, 然后在指定文件夹下新增一个文件后本地下载正常, 打包后下载出现问题: 下载该文件时, 后端抛出异常, 异常如下
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 地址对应的资源是文件, 所以直接返回这个文件
- 后续源码如何返回这个文件可以自己继续深入
对问题部分远程断点调试:
- 依旧是进入 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内的文件, 然后通过输出流将其输出.
修改后的代码
@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;
}
相关文章
- 好机会!互联网IT人才速看!纳入工信部区块链产业人才库!8月27日报名截止
- 如何推进IT运维数据中心问题管理
- Mac录屏软件:Record It[通俗易懂]
- 清华2022就业报告出炉!本硕毕业生超33%首选IT大厂,博士一半留京
- redis 5.0.7: MISCONF Redis is configured to save RDB snapshots, but it is currently not able to pers
- 新变更新版红帽Linux:改变世界IT发展步伐(红帽linux版本)
- Oracle管理权限:全面加强IT安全(oracle管理权限)
- 智能运维!中国联通里程碑式开启网络IT化转型
- 一个IT从业人员的职业道德与素养
- Troubleshooting Error 1135 in MySQL: How to Solve It and Get Your Database Back on Track(mysql1135)
- 小红帽Linux中文:开源技术趋势下诞生的全面IT办公利器(小红帽linux中文)
- 企业云 2.0:VMware 眼中的企业 IT 的未来
- Linux行为管理:构建安全可靠的IT系统(linux 行为 管理)
- 型MS SQL数据库类型助你实现IT梦想(mssql类)
- Cisco和Oracle共同推进IT领域发展(cisco和oracle)
- Oracle数据库培训提升IT技能创造价值(it oracle 培训)
- 携程推出Redis,助你成就IT卓越(携程 redis)
- 打开Oracle MOAC,解锔新时代IT之路(oracle moac)
- Oracle 11 企业版革命性IT解决方案(oracle11企业版)
- 鸿蒙出世,金融IT人最关心哪三个问题?