问题描述
我正在尝试下载由我编写的 REST API 生成的 zip 文件(此 REST API 工作正常,我可以从邮递员那里下载 zip 文件)。
@GetMapping(value = "/zipDownloadGraphQLSchema",produces = "application/zip")
public void zipDownloadGraphQLSchema(@RequestBody SchemaGeneratorInput schemaGeneratorInput,HttpServletResponse response) {
long currentRequestTimeInMillis = System.currentTimeMillis();
String fileBasePath = service.generateGraphQLSchemaFiles(schemaGeneratorInput,currentRequestTimeInMillis);
fileBasePath += "/";
File directoryPath = new File(fileBasePath);
String[] files = directoryPath.list();
try {
ZipOutputStream zipOut = new ZipOutputStream(response.getoutputStream());
for (String fileName : Objects.requireNonNull(files)) {
FileSystemResource resource = new FileSystemResource(directoryPath + "/" + fileName);
ZipEntry zipEntry = new ZipEntry(Objects.requireNonNull(resource.getFilename()));
zipEntry.setSize(resource.contentLength());
zipOut.putNextEntry(zipEntry);
StreamUtils.copy(resource.getInputStream(),zipOut);
zipOut.closeEntry();
}
zipOut.finish();
zipOut.close();
response.setContentType("application/force-download");
response.setStatus(HttpServletResponse.SC_OK);
response.addheader(HttpHeaders.CONTENT_disPOSITION,"attachment; filename=\"GraphQLSchema.zip\"");
} catch (Exception e) {
log.error(e.getMessage());
throw new BusinessException(HttpStatus.INTERNAL_SERVER_ERROR.value(),Constants.ERROR_PROCESSING_REQUEST);
} finally {
try {
FileUtils.deleteDirectory(new File(fileBasePath));
} catch (IOException e) {
log.error(e.getMessage());
// throw new BusinessException(HttpStatus.INTERNAL_SERVER_ERROR.value(),Constants.ERROR_DELETING_USER_FOLDER);
}
}
}
基于以下几个解决方案,我尝试了 2 种编写 客户端 的方法:
- How to programmatically consume a file from a Rest API using Spring?
- https://www.leveluplunch.com/java/tutorials/038-retrieve-file-spring-resttemplate/
- Download Large file from server using REST template Java Spring MVC
方法 1(非流式传输):
public ResponseEntity<String> callGraphQlFileSGen1(GraphQlFileGenRequest request,String correlationId) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM));
//headers.setAccept(Arrays.asList(MediaType.ALL));
//headers.add("Content-Type","application/zip");
headers.setContentType(MediaType.APPLICATION_JSON);
httpentity<GraphQlFileGenRequest> entity = new httpentity<>(request,headers);
ResponseEntity<byte[]> response = null;
try {
response = restTemplate.exchange(graphQlFileGenPath,HttpMethod.GET,entity,byte[].class,"1");
} catch (Exception e) {
LOGGER.error("Failed to call graphQlApiGen. {}",e.toString());
throw e;
}
if (response.getStatusCode().equals(HttpStatus.OK)) {
try {
FileOutputStream output = new FileOutputStream(
new File(graphQlFileDownloadpath + "/GraphQlSchema.zip"));
IoUtils.write(response.getBody(),output);
} catch (IOException e) {
LOGGER.error("Unable to write graphQl file. {}",e.toString());
e.printstacktrace();
throw e;
}
}
return ResponseEntity.status(HttpStatus.OK).headers(headers).body("{}");
}
我常用的 RestTemplate 代码:
@Bean("mtlsRestTemplate")
public RestTemplate getMtlsRestTemplate() throws Exception {
Resource resource = resourceLoader.getResource("classpath:" + mtlsKeystorePath);
KeyStore keystore = KeyStore.getInstance("jks");
InputStream inputStream = null;
try {
inputStream = resource.getInputStream();
keystore.load(inputStream,mtlsKeyStorePassword.tochararray());
} finally {
if (null != inputStream) {
inputStream.close();
}
}
SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keystore,mtlsKeyStorePassword.tochararray())
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(factory);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new MappingJackson2HttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
// Add the message converters to the restTemplate
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
方法 2(流媒体):
public ResponseEntity<String> callGraphQlFileSGen2(GraphQlFileGenRequest request,String correlationId)
throws JsonProcessingException {
HttpHeaders dummyHeaders = new HttpHeaders();
ObjectMapper objectMapper = new ObjectMapper();
BodySettingRequestCallback requestCallBack = null;
try {
requestCallBack = new BodySettingRequestCallback(objectMapper.writeValueAsstring(request),objectMapper);
} catch (JsonProcessingException e1) {
LOGGER.error("Couldn't write value as string for request. {}",e1.toString());
e1.printstacktrace();
throw e1;
}
// Streams the response instead of loading it all in memory
ResponseExtractor<Void> responseExtractor = response -> {
// Response written to a file
Path path = Paths.get(graphQlFileDownloadpath + "/GraphQlSchema.zip");
Files.copy(response.getBody(),path);
return null;
};
try {
restTemplate.execute(URI.create(graphQlFileGenPath),requestCallBack,responseExtractor);
} catch (Exception e) {
LOGGER.error("Error downloading GraphQl file. {}",e.toString());
e.printstacktrace();
throw e;
}
return ResponseEntity.status(HttpStatus.OK).headers(dummyHeaders ).body("{}");
}
BodySettingRequestCallback.class
public class BodySettingRequestCallback implements RequestCallback {
private String body;
private ObjectMapper objectMapper;
public BodySettingRequestCallback(String body,ObjectMapper objectMapper) {
this.body = body;
this.objectMapper = objectMapper;
}
@Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM,MediaType.ALL));
byte[] json = getEventBytes();
request.getBody().write(json);
}
byte[] getEventBytes() throws JsonProcessingException {
return objectMapper.writeValueAsBytes(body);
}
}
对于 Approach-1,我收到以下错误:
org.springframework.web.client.HttpClientErrorException$NotAcceptable: 406 : [no body]
对于 Approach-2 我收到以下错误:
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 : [no body]
过去 1 天我一直被这个问题困扰。对此的任何解决方案/建议将不胜感激。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)