一. 服务环境:
spring cloud 微服务 jar 方式进行部署。
二. 文件在项目中的位置:
三. 情景再现:
在内网本地测试环境(因为小程序需要https认证的服务才能交互,小程序无法在内网给测试测,因此没有打jar包进行测试),在idea中使用下面方式与前端进行联调,使用花生壳进行外网映射,接收微信回调,一切进行的都很顺利。
public WXConfig() throws Exception {
//从微信商户平台下载的安全证书存放的路径
// 获取URL
URL url = getClass().getClassLoader().getResource("apiclient_cert.p12");
// 通过url获取File的绝对路径
File file = new File(url.getFile());
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
等部署到外网环境进行测试的时候,进行退款的时候必须认证证书,可是证书却获取不到,出现以下异常:
java.io.FileNotFoundException: file:/usr/local/package_project/xuanle-prod2/business-xuanle-service-prod2.jar!/BOOT-INF/classes!/apiclient_cert.p12 (No such file or directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at com.project.util.wx.WXConfig.<init>(WXConfig.java:31)
at com.project.service.wx.MiniPayService.refundToWeixin(MiniPayService.java:306)
at com.project.service.wx.MiniPayService.refund(MiniPayService.java:288)
at com.project.controller.wx.MiniProgramController.miniRefund(MiniProgramController.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
四. 解决问题
然后想办法解决问题,我们使用maven将项目打成jar包时,此时的 .jar是一个可执行文件。虽然通过之前的方式可以拿到证书的路径,但是却无法通过new File(String filePath)
获取路径中的文件。因为 .jar本身就是一个可执行文件,又怎么从文件中获取文件呢?
既然ClassLoad
能获取文件,那就通过他来获取文件流,在通过文件流转换成字节数组就完美解决问题!
public WXConfig() throws Exception {
//从微信商户平台下载的安全证书存放的路径
InputStream certStream = WXConfig.class.getClassLoader().getResourceAsStream("apiclient_cert.p12");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int ch;
while ((ch = certStream.read(buffer)) != -1) {
outputStream.write(buffer,0, ch);
}
this.certData = outputStream.toByteArray();
certStream.read(this.certData);
certStream.close();
}