场景:使用springboot搭建Fabric-java-sdk的客户端项目,需要将Fabric网络生成的密钥和证书的文件夹拷贝到项目的资源目录或者config包下,在配置文件中配置各种证书的路径,然后在代码中通过这个配置文件获取这些路径,从而读取这些文件并验证密钥和证书。本地是没有问题的,但打成jar包发布到linux测试环境就会出现文件空指针等问题。
分析:部署方式是springboot打成jar包放在Linux运行,而在Linux中无法直接访问未经解压的文件,所以就会找不到文件。springboot内置tomcat,打包后是一个jar包,无法直接读取jar包中的文件,读取只能通过类加载器读取。
解决:只能使用流的方式对资源文件进行读取和处理。
springboot项目的目录结构和配置文件内容如下:
1、首先解决读取configure-tls.yml文件的问题:
使用new File( "filepath" )是行不通的,因此需要通过ClassPathResource获取流,从而读取yml文件的内容。
@Component
public class Configurations {
public static JsonObject loadConfigurations() throws IOException {
ClassPathResource classPathResource = new ClassPathResource("configure-tls.yml");
InputStream stream = classPathResource.getInputStream();
Yaml yaml = new Yaml();
Map<String, Object> configYaml = yaml.load(stream);
JsonObject configJSON = Json.createObjectBuilder(configYaml).build();
return configJSON;
}
}
当然还有其他的方式,不过都是通过获取流来读取文件内容的。底层都是通过类加载器读取文件流,类加载器可以读取jar包中的编译后的class文件,当然也是可以读取jar包中的资源文件。
InputStream inputStream = this.getClass().getResourceAsStream("configure-tls.yml");
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("configure-tls.yml");
2、解决遍历文件获取以"_sk"为后缀的密钥文件问题。
因为生成的私钥文件的文件名称是不固定的,如9898c99be81836d8539d28f5184b0b69d89f97ce7a20eef4de5f74cbc87f9f4b_sk。所以在代码中的处理是根据后缀为"_sk"来确定的,而在linux环境是无法遍历jar包下的文件夹和处理文件的。本地处理的代码如下:
private static File getKeyFilesInDir(File filePath) {
File keyFile = null;
File[] listFiles = filePath.listFiles();
if (listFiles != null) {
for (File file : listFiles) {
if (file.isFile()) {
if (file.getName().endsWith("_sk")) {
keyFile = file;
break;
}
}
}
}
return keyFile;
}
由于思维的局限性,一直在想着如何获取jar包中某包下的以"_sk"后缀的文件,各种尝试各种不行,包括"/*_sk",均失败。冷静了一下,发现密钥和证书的文件夹不一定要打进jar包中,放到linux系统下的固定路径不就可以了,而且此时就可以使用绝对路径以及File对象来处理文件。以上代码都不用修改了。如图一,注释掉的是本地开发配置的路径,linux环境使用的是linux系统下的绝对路径,以后Fabric网络重启或者重新生成密钥证书时,只用将crypto-config文件夹拷贝到"/usr/software"下即可。定式思维的可怕,自己给自己上了一课,也许一直钻牛角尖能解决,但肯定不如这个来的优雅,省时高效!!