Java 8 Spring Boot如何读取Resources下的整个文件夹?
问题原因及解决方案
为什么原代码无法运行
当Spring Boot项目打包成.jar文件后,/client_cert是jar压缩包内部的资源路径,并非操作系统文件系统中的实际目录:
- 使用
getResource("/client_cert").toURI()会返回jar:协议的URI,这种URI不是分层的文件系统URI,因此new File(URI)会抛出IllegalArgumentException: URI is not hierarchical。 - 调用
getFile()返回的是jar内部的虚拟路径,并非真实文件,所以listFiles()会返回null。 getResourceAsStream()只能读取单个资源,无法直接遍历目录下的所有文件,因此单独使用它无法解决批量读取的问题。
正确的解决方案:使用Spring资源加载器遍历证书
Spring提供的ResourcePatternResolver可以完美处理jar内部的资源遍历,无需依赖文件系统的File对象。修改代码如下:
package my.app.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import java.io.InputStream; @Configuration public class ClientSSLConfig { @Bean public void getCertificates() { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); try { // 匹配classpath下client_cert目录中的所有文件 Resource[] certResources = resolver.getResources("classpath:client_cert/*"); for (Resource resource : certResources) { // 通过Resource对象获取证书输入流和文件名 try (InputStream is = resource.getInputStream()) { loadCerts(is, resource.getFilename()); } } } catch (Exception e) { throw new RuntimeException("加载客户端证书失败", e); } } // 调整loadCerts方法,接收输入流和文件名(替代原File参数) private void loadCerts(InputStream certInputStream, String fileName) throws Exception { // 这里编写你的证书加载逻辑,例如: // CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); // X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(certInputStream); // 将证书添加到Java Keystore的逻辑... } }
关键说明
PathMatchingResourcePatternResolver支持classpath:通配符匹配,能自动识别jar内部的资源。- 通过
Resource.getInputStream()读取证书内容,无需依赖文件系统中的真实文件。 - 使用try-with-resources语法自动关闭输入流,避免资源泄漏。
备选方案:纯JDK方式遍历Jar内资源(不依赖Spring)
如果不想使用Spring的工具类,可以通过JDK的JarFile遍历jar中的条目,但实现相对繁琐:
private void scanCertificatesInJar() throws Exception { String jarPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); try (JarFile jarFile = new JarFile(jarPath)) { Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String entryName = entry.getName(); // 筛选client_cert目录下的证书文件 if (entryName.startsWith("client_cert/") && !entry.isDirectory()) { try (InputStream is = jarFile.getInputStream(entry)) { loadCerts(is, entryName.substring(entryName.lastIndexOf("/") + 1)); } } } } }
这种方法需要处理jar路径的解析,且仅适用于jar包运行的场景,不如Spring方案通用。
内容的提问来源于stack exchange,提问作者Vitor
相关产品推荐
相关产品推荐

