Spring Boot项目Jar运行时如何遍历resources下的rules文件夹执行SQL
解决方案
问题根因
Spring Boot 打包为jar包后,内部资源以嵌套形式存储在jar归档文件中,不属于操作系统文件系统的普通文件/目录,因此无法通过
java.io.FileAPI直接读取、遍历,这就是IDE运行正常、jar运行失败的核心原因。
实现方案
采用Spring内置的ResourcePatternResolver实现classpath资源的递归扫描,通过流的方式读取文件内容,兼容IDE和jar两种运行环境。
修改后的代码实现
import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; private static final String RULES_SCAN_PATH = "classpath*:/rules/**/*"; private static final String INSERT_SUFFIX = ".insert"; private static final String TAB = "\t"; private void loadDb() { log.info("Hello!"); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); try { // 递归扫描rules目录下所有资源 Resource[] resources = resolver.getResources(RULES_SCAN_PATH); log.info("**********************************************"); log.info("Total resources found under rules directory: {}", resources.length); log.info("**********************************************"); for (Resource resource : resources) { if (!resource.isReadable()) continue; String fullPath = resource.getURI().toString(); // 只处理后缀为.insert的SQL文件 if (!fullPath.endsWith(INSERT_SUFFIX)) continue; // 提取相对路径计算层级,实现缩进展示 String relativePath = fullPath.substring(fullPath.indexOf("/rules/") + 7); int level = (int) relativePath.chars().filter(c -> c == '/').count(); for (int i = 0; i < level; i++) { System.out.print(TAB); } String fileName = relativePath.substring(relativePath.lastIndexOf("/") + 1); log.info(fileName); // 以流的形式读取文件内容执行SQL try (InputStream inputStream = resource.getInputStream()) { executeSqlStatements(inputStream); } } } catch (IOException e) { log.error("Load rules directory failed", e); } } // 修改原SQL执行方法,接收InputStream参数读取内容 private void executeSqlStatements(InputStream inputStream) throws IOException { // 示例:读取流内容为SQL字符串,可替换为你原有逐行读取逻辑 String sqlContent = org.apache.commons.io.IOUtils.toString(inputStream, StandardCharsets.UTF_8); // 原有SQL执行逻辑保持不变即可 }
注意事项
- 原有代码中字符串比较使用
==不符合Java语法规范,字符串内容比较需使用equals()方法,本次优化采用endsWith()直接判断后缀,逻辑更稳妥。 - 确保构建配置中没有排除
src/main/resources/rules目录的打包规则,默认Spring Boot会自动打包该目录下的所有资源。 - 如果需要完全还原原有先打印目录、再打印子文件的层级展示效果,可以先将扫描到的资源路径整理为树形结构,再递归遍历输出即可。
内容的提问来源于stack exchange,提问作者Pratik Shekhar
相关产品推荐
相关产品推荐

