You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot打包Jar后如何读取resources/key目录下的资源?

Spring Boot Jar包中读取resources下密钥文件的正确方式

问题原因

项目打包成Jar后,resources目录下的资源不再是文件系统中的独立文件,而是嵌入在Jar包内部的条目。原代码依赖文件系统路径的Paths.get()和Files.readAllBytes()方法,自然会失效。

解决方案

方式一:原生Java API读取(通用所有Java项目)

通过ClassLoader.getResourceAsStream()获取资源输入流,再将流转换为字符串,完全适配Jar包环境:

修改你的密钥内容获取方法:

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

private String getPublicKeyContent() throws IOException {
    // 从classpath根目录读取资源,路径无需带开头/
    try (InputStream is = getClass().getClassLoader().getResourceAsStream("key/public.pem")) {
        if (is == null) {
            throw new IOException("公钥文件未找到:classpath:key/public.pem");
        }
        // Java 9+ 可用InputStream.readAllBytes()直接读取
        return new String(is.readAllBytes(), StandardCharsets.UTF_8);
    }
}

private String getPrivateKeyContent() throws IOException {
    try (InputStream is = getClass().getClassLoader().getResourceAsStream("key/private.pem")) {
        if (is == null) {
            throw new IOException("私钥文件未找到:classpath:key/private.pem");
        }
        return new String(is.readAllBytes(), StandardCharsets.UTF_8);
    }
}

如果使用Java 8及以下版本,需要手动逐行读取流:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

private String getPublicKeyContent() throws IOException {
    try (InputStream is = getClass().getClassLoader().getResourceAsStream("key/public.pem");
         BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
        if (is == null) {
            throw new IOException("公钥文件未找到:classpath:key/public.pem");
        }
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }
        return sb.toString();
    }
}

方式二:Spring Boot专属方式(适配Spring生态)

如果你的类是Spring管理的Bean,可以注入ResourceLoader来读取资源,更贴合Spring Boot的使用习惯:

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

@Component
public class KeyLoader {

    private final ResourceLoader resourceLoader;

    // 构造方法注入ResourceLoader
    public KeyLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    private String getPublicKeyContent() throws IOException {
        Resource resource = resourceLoader.getResource("classpath:key/public.pem");
        if (!resource.exists()) {
            throw new IOException("公钥文件未找到:classpath:key/public.pem");
        }
        return new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
    }

    private String getPrivateKeyContent() throws IOException {
        Resource resource = resourceLoader.getResource("classpath:key/private.pem");
        if (!resource.exists()) {
            throw new IOException("私钥文件未找到:classpath:key/private.pem");
        }
        return new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
    }

    // 你原有的getPublicKey和getPrivateKey方法保持不变
    public PublicKey getPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        String key = getPublicKeyContent().replaceAll("\\n", "")
                .replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "");

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(key));
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(keySpec);
    }

    public PrivateKey getPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        String key = getPrivateKeyContent().replaceAll("\\n", "")
                .replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "");

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key));
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(keySpec);
    }
}

注意事项

  • 资源路径不要以/开头:getClassLoader().getResourceAsStream("key/private.pem")是正确写法,带/会导致资源找不到。
  • 确保打包时资源被正确包含:Maven/Gradle默认会打包src/main/resources下的所有内容,无需额外配置,除非你修改了资源目录规则。
  • 必须关闭输入流:使用try-with-resources语法自动关闭流,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Jack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:55:21