生成临时文件
项目中,有一个业务,需要请求一个三方的https接口,上传一个.dcm文件,返回一个png文件。这个.dcm文件,会经过我们自己的Springboot服务,然后调用第三方的https接口。一开始我们使用的方法是:上传一个.dcm文件到我们的Springboot服务,然后生成一个临时文到客户分配OpenShift的PVC文件夹中,再通过这个临时文件构建FileSystemResource,去请求第三方的接口
// 模拟代码如下
void contextLoads() {
//模拟当时流程,上传一个.dcm问津,获取一个文件流。
try (FileInputStream fileInputStream = new FileInputStream(filePath)) {
// 拿到文件流后会生成一个临时文件
File template = File.createTempFile("template", ".dcm",new File(PVC_Path));
// 写入临时文件
try (FileOutputStream fileOutputStream = new FileOutputStream(template)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, bytesRead);
}
// 模拟请求第三方的接口,返回图片
WebClient webClient = WebClient.create("http://localhost:8080/file");
// 构建 multipart 请求体
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", new FileSystemResource(template));
// 请求第三方的接口
Mono<Resource> resourceMono = webClient.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(Resource.class);
resourceMono.subscribe(resource -> {
log.info("接收到了文件流");
});
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
// 删除临时文件
template.deleteOnExit();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
绕过生成临时文件,通过ByteArrayResource调用附件上传接口
然而,以外发生了。。。返回的.png文件,自己单元测试都是ok的,但是放到OpenShift中,图片就只有几K(正常应该是在1M左右),上PVC排查,发现有0K的临时文件,怀疑上传到PVC时,有异常。删掉template.deleteOnExit(),上PVC产看临时文件,果然是0K。由于我们的权限有限,最多看下pod的日志和pod内部的环境。所以有了第二种上传附件的方式
// 尝试绕过在PVC创建临时文件,既然我们能拿到文件,就通过文件流的形式请求接口
void uploadWithByte() {
//模拟当时流程,会从一个https的请求,获取一个流,这里用文件流替代。
try (FileInputStream fileInputStream = new FileInputStream(filePath)) {
// 直接把文件流转成byte[]
byte[] fileBytes = fileInputStream.readAllBytes();
// 模拟请求第三方的接口,返回图片
WebClient webClient = WebClient.create("http://localhost:8080/file");
// 构建 multipart 请求体
MultipartBodyBuilder builder = new MultipartBodyBuilder();
// 构建ByteArrayResource
builder.part("file", new ByteArrayResource(fileBytes){
@Override
public String getFilename() {
return "template.dcm";
}
});
// 请求第三方的接口
Mono<Resource> resourceMono = webClient.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(Resource.class);
resourceMono.subscribe(resource -> {
log.info("接收到了文件流");
});
} catch (IOException e) {
throw new RuntimeException(e);
}
}
通过这种方式,可以无需在PVC中生成临时文件。而且代码也简单很多