I want to return a generated pdf file via spring-mvc-rest controller. This is a shortened version of the code I'm currently using:
@RestController
@RequestMapping("/x")
public class XController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ResponseEntity<byte[]> find() throws IOException {
byte[] pdf = createPdf();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "pdf"));
headers.setContentDispositionFormData("attachment", "x.pdf");
headers.setContentLength(pdf.length);
return new ResponseEntity<byte[]>(pdf, headers, HttpStatus.OK);
}
}
This works almost fine, it just to return the actual byte array as base64 encoded :(
curl -i 'http://127.0.0.1:8080/app/x'
Server: Apache-Coyote/1.1
Content-Disposition: form-data; name="attachment"; filename=x.pdf"
Content-Type: application/pdf
Content-Length: 138654
Date: Fri, 08 Jan 2016 11:25:38 GMT
"JVBERi0xLjYNJeLjz9MNCjMyNCAwIG9iag [...]
(btw. the response doesn't even contain a closing "
:)
Any hints appreciated!
Now, you don't need to use the @Controller and the @RestponseBody annotation. Instead you can use the @RestController to provide the same functionality. In short, it is a convenience controller which combines the behavior of the @Controler and the @Response body into one.
The JSON format natively doesn't support binary data. The binary data has to be escaped so that it can be placed into a string element (i.e. zero or more Unicode chars in double quotes using backslash escapes) in JSON. An obvious method to escape binary data is to use Base64.
Spring RestController annotation is used to create RESTful web services using Spring MVC. Spring RestController takes care of mapping request data to the defined request handler method. Once response body is generated from the handler method, it converts it to JSON or XML response.
@RestController is not meant to be used to return views to be resolved. It is supposed to return data which will be written to the body of the response, hence the inclusion of @ResponseBody .
I created the example using your code, but a very similar method is doing his job in my web application:
@RequestMapping(value = "/", method = RequestMethod.GET)
public void downloadFile(HttpServletResponse response,
HttpServletRequest request) throws IOException
{
byte[] pdf = createPdf();
response.setContentType("application/x-download");
response.setHeader("Content-Disposition", "attachment; filename=foo.pdf");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.getOutputStream().write(pdf);
}
Else you can try this answer Open ResponseEntity PDF in new browser tab
The problem is caused by Spring trying to encode the response as Json.
Your request probably specifies Accepts = "*/*"
and since Spring ignores the ResponseEntity's ContentType
, the best encoding is found to be application/json
.
The simplest fix to this is to add a produces
to your request mapping, so your code becomes:
@RestController
@RequestMapping(value = "/x",
produces = "application/pdf") // <-- Add this
public class XController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ResponseEntity<byte[]> find() throws IOException {
byte[] pdf = createPdf();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
headers.setContentDispositionFormData("attachment", "x.pdf");
headers.setContentLength(pdf.length);
return new ResponseEntity<byte[]>(pdf, headers, HttpStatus.OK);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With