Spring Boot读取本地PNG抛出NoSuchFileException异常
问题说明
程序访问产品图片接口时抛出异常:java.nio.file.NoSuchFileException: C:\Users\PC\Desktop\
场景为给数据库所有产品配置PNG格式图片时,Spring Boot无法识别目标文件路径或文件本身。已做的尝试包括:
- 所有Product实体的
photoName属性均赋值为unknown.png,和目标文件名完全匹配,文件本身为PNG格式 - 多次调整路径书写格式、对路径对象调用
toString()方法 - 访问
localhost:8000/photoProduct/1接口始终抛出相同异常,预期该接口可正常展示对应产品图片
对应接口实现代码如下:
@RestController public class CatalogueRestController { @Autowired private ProductRepository productRepository; @GetMapping(path="/photoProduct/{id}",produces = MediaType.IMAGE_PNG_VALUE) public byte[] getPhoto(@PathVariable("id") Long id) throws Exception{ Product p=productRepository.findById(id).get(); return Files.readAllBytes(Paths.get("C:/Users/PC/Desktop/info1/ecom/products/unknown.png")); } }
排查思路
按优先级依次排查以下问题点:
- 校验运行代码版本一致性:你抛出的异常提示缺失路径为
C:\Users\PC\Desktop\,但贴出的代码里配置的路径包含后续info1/ecom/products/unknown.png层级,两者不匹配,大概率是修改代码后未重新编译、未重启服务,实际运行的是旧版本class文件 - 校验路径真实有效性:直接复制代码中
Paths.get()传入的完整路径,粘贴到Windows资源管理器地址栏回车,确认是否能直接定位到目标PNG文件。常见错误包括路径层级拼写错误、文件夹名写错、系统实际用户名不是PC导致根路径错误 - 校验文件扩展名真实性:Windows默认开启「隐藏已知文件类型扩展名」,很可能你肉眼看到的
unknown.png实际全名为unknown.png.png,真实文件名和代码中配置的名称不匹配 - 校验文件访问权限:确认运行Spring Boot进程的系统账号,对目标PNG文件有读取权限,若文件被其他程序独占锁定、或权限配置为禁止当前账号读取,也会抛出文件不存在异常
- 校验代码逻辑合理性:当前代码硬编码了全路径,完全没有用到从数据库查询出的Product对象的
photoName属性,先确认硬编码路径本身的正确性,再关联数据库字段逻辑
解决方案
- 先解决代码版本不一致问题:执行
mvn clean compile(如果是Gradle项目执行gradle clean build)清空旧编译产物,重新启动Spring Boot应用后再测试接口 - 替换硬编码路径的获取方式:不要手动敲系统路径,打开存放
unknown.png的文件夹,按住Shift右键点击目标文件,选择「复制为路径」,将复制得到的完整路径去掉前后包裹的引号后,替换Paths.get()方法内的参数 - 关闭Windows的扩展名隐藏功能,打开文件资源管理器的「查看」选项卡,勾选「文件扩展名」,确认目标文件真实名称和代码中配置的文件名完全一致,没有重复后缀
- 优化代码健壮性:不要直接调用
findById(id).get(),如果对应ID的产品不存在会抛出非预期的NoSuchElementException,改用orElseThrow()做存在性校验;生产环境不建议把静态资源存在桌面这类系统目录,可将图片放到项目resources/static目录下通过类路径读取,避免不同部署环境的系统路径差异,优化后的代码示例:
@RestController public class CatalogueRestController { @Autowired private ProductRepository productRepository; @GetMapping(path="/photoProduct/{id}",produces = MediaType.IMAGE_PNG_VALUE) public byte[] getPhoto(@PathVariable("id") Long id) throws Exception{ Product p = productRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("对应ID的产品不存在")); // 读取resources/static/products目录下的对应图片 Path imgPath = Paths.get(getClass().getClassLoader() .getResource("static/products/" + p.getPhotoName()).toURI()); return Files.readAllBytes(imgPath); } }
内容的提问来源于stack exchange,提问作者Salah
相关产品推荐
相关产品推荐

