Spring Boot中Maven未复制资源文件及读取异常问题求助
问题回顾
你在Spring Boot项目中尝试读取src/main/resources下的JSON文件,使用了这段代码:
File file = new File(this.getClass().getClassLoader().getResource(inputFileName).getFile());
但通过Spring Tools以「Run As -> Spring Boot App」运行时,抛出了NoSuchFileException,发现target/classes目录里并没有你的JSON文件。同时你的Maven classpath配置里包含了src/main/resources的条目,但文件就是没被复制过去。
为什么Maven没复制文件到target/classes?
看你提供的classpath配置里这一行:
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
问题出在excluding="**"这个属性上!它表示排除src/main/resources目录下的所有文件和子目录,Maven自然不会把任何资源文件复制到target/classes里。
正常情况下,src/main/resources是Maven默认的资源目录,不需要额外添加排除规则,这个配置应该是误加的。
解决步骤
第一步:修复Maven classpath配置
把src/main/resources条目里的excluding="**"去掉,修改后的配置如下:
<classpathentry kind="src" output="target/classes" path="src/main/resources"> <attributes> <attribute name="maven.pomderived" value="true"/> </attributes> </classpathentry>
然后执行mvn clean compile命令,Maven就会把src/main/resources下的文件复制到target/classes目录了。
第二步:改用Spring Boot推荐的资源读取方式(重要)
即使修复了classpath问题,你原来用new File()的方式也有隐患——当项目打包成jar包后,jar内部的资源并不是文件系统中的真实文件,这时候getFile()会返回一个奇怪的路径,依然会抛出异常。
推荐用以下几种方式读取资源:
方式1:注入ResourceLoader读取
这是最灵活的方式,适合动态指定文件名的场景:
import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Component; import java.io.InputStream; @Component public class JsonResourceReader { private final ResourceLoader resourceLoader; // 构造注入ResourceLoader public JsonResourceReader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public void readJson(String fileName) throws Exception { // 用classpath:前缀指定资源位置 Resource resource = resourceLoader.getResource("classpath:" + fileName); try (InputStream inputStream = resource.getInputStream()) { // 这里可以用Jackson/Gson等框架解析JSON // 示例:ObjectMapper mapper = new ObjectMapper(); // YourDto dto = mapper.readValue(inputStream, YourDto.class); } } }
方式2:用@Value直接注入资源
如果文件名是固定的,这种方式更简洁:
import org.springframework.core.io.Resource; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.io.InputStream; @Component public class FixedJsonReader { // 直接注入指定的资源 @Value("classpath:your-target-file.json") private Resource jsonResource; public void loadJson() throws Exception { try (InputStream inputStream = jsonResource.getInputStream()) { // 处理JSON流 } } }
方式3:传统的流读取方式(无Spring依赖时用)
如果不想依赖Spring的API,也可以用类加载器的流读取方式:
try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(inputFileName)) { if (inputStream == null) { throw new FileNotFoundException("无法找到资源文件: " + inputFileName); } // 处理输入流 }
总结
- 先修复classpath的排除规则,让Maven正确复制资源文件;
- 优先使用Spring提供的
Resource相关API读取资源,适配本地开发和jar包运行两种场景; - 避免用
File对象读取classpath资源,因为jar环境下不支持。
内容的提问来源于stack exchange,提问作者user5155835

