'How do I retrieve Resource object using restTemplate in Spring Boot?
So, basically the title.
I got 2 microservices. One generates and sends a zip file and the other one receives it, then does some magic, converts it to an array[] of bytes and then sends it somewhere else. But it's just in theory - I coldn't make it work.
I need to download a Resource (https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/resources.html) that contains InputStream that my generated zip archive is wrapped into. Writing it inside OutputStream of a HttpServletResponse doesn't work for me since I can't use it - later on I need to manipulate the file and this approach is for browser download only (?)
So I did this in the first microservice:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(baos);
ZipOutputStream zos = new ZipOutputStream(bos);
try {
zos = service.generateZip(blablabla, zos);
baos.close();
bos.close();
zos.close();
} catch (Exception e) {
e.printStackTrace();
}
ByteArrayResource resource = new ByteArrayResource(baos.toByteArray());
ResponseEntity<Resource> response = ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/zip;charset=UTF-8"))
.contentLength(resource.contentLength())
.header(HttpHeaders.CONTENT_DISPOSITION,
ContentDisposition.parse(format("attachment; filename=\"doc_%s.zip\"", id)).toString())
.body(resource);
And this in second:
public byte[] getZip(DocRequest request) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/zip;charset=UTF-8"));
headers.setAccept(Collections.singletonList(MediaType.parseMediaType("application/zip;charset=UTF-8")));
// headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// headers.setAccept(Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM));
Resource response = restTemplate.exchange(
apiUrl + "/doc/get-zip/" + request.getId(),
HttpMethod.GET,
new HttpEntity<>(null, headers),
Resource.class)
.getBody();
return (response != null) ? IOUtils.toByteArray(response.getInputStream()) : null;
}
also added ResourceHttpMessageConverter to a restTemplate to configs of both microservices:
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
converter.setObjectMapper(objectMapper);
ResourceHttpMessageConverter resourceConverter = new ResourceHttpMessageConverter();
resourceConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
return builder.interceptors(...)
.messageConverters(resourceConverter, converter)
.configure(restTemplate);
Without them I get an error which looks like this:
{"method":"POST","exceptionName":"RestClientException","detail":"Error while extracting response for type [interface org.springframework.core.io.Resource] and content type [application/octet-stream]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid UTF-8 middle byte 0x59; nested exception is com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 middle byte 0x59\n at [Source: (ByteArrayInputStream); line: 1, column: 13]"}
or
{"method":"POST","exceptionName":"RestClientException","detail":"Error while extracting response for type [interface org.springframework.core.io.Resource] and content type [application/zip;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid UTF-8 start byte 0x91; nested exception is com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 start byte 0x91\n at [Source: (ByteArrayInputStream); line: 1, column: 12]"}
depending on contentType (application/octet-stream and application/zip (application/zip;charset=UTF-8) respectively).
After I added ResourceHttpMessageConverter it now gives me
{"method":"POST","exceptionName":"RestClientException","detail":"Error while extracting response for type [interface org.springframework.core.io.Resource] and content type [application/octet-stream]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token 'PK\u0003..': was expecting ('true', 'false' or 'null'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'PK\u0003...': was expecting ('true', 'false' or 'null')\n at [Source: (ByteArrayInputStream); line: 1, column: 28]"}
Maybe I am using something wrong? Any advice would be appreciated. Thank you in advance
Solution 1:[1]
Ended up encoding byte array to base64 string then sent it as
return ResponseEntity.ok().body(Base64Utils.encodeToString(baos.toByteArray()));
Then in my receiving microservice I added the following to my restTemplate config:
// idk if it's need to put StringHttpMessageConverter first in the list, but I did it just in case
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
And it worked!
Don't know if it's right, but maybe someone will find it helpful
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
