Issue
I'm trying to build a small web application using spring-mvc,spring-boot and spring security. Only one controller is used and one of the service end-point is to let user download a docx file generated by the web application. My logic code works well, the problem is that when I want to add Headers to HttpServletResponse, addHeader() and setHeader() don't work, I just want to specify a name for the download file. I printed some logs and got no clue why this is not working.
Here is part code of my controller:
@Controller
public class ImportExportController {
private final static Logger LOGGER = LoggerFactory.getLogger(ImportExportController.class);
@Autowired
private WordProcessor wordProcessor;
@RequestMapping("/export")
public void export(@RequestParam(value = "domainName", required = true) String domainName,
@RequestParam(value = "projectName", required = true) String projectName,
@RequestParam(value = "testFolderId", required = true) int testFolderId,
HttpServletRequest request, HttpServletResponse response) {
String exportedFileName = "exportedTC_" + domainName + "_" + projectName + "_"
+ Integer.toString(testFolderId) + ".docx";
try {
extendExpiredALMSession();
SaveToZipFile saver = wordProcessor.ExportToWord(domainName, projectName,
Integer.toString(testFolderId));
saver.save(response.getOutputStream());
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
LOGGER.info("exportedFileName: " + exportedFileName);
LOGGER.info("contains: " + response.containsHeader("Content-Disposition"));
response.addHeader("Content-Disposition", "attachment; filename=\"" + exportedFileName + "\"");
for (String name : response.getHeaderNames()) {
LOGGER.info("Header: " + name);
}
LOGGER.info("Date Header:" + response.getHeader("Date"));
LOGGER.info("Content-Disposition header: " + response.getHeader("Content-Disposition"));
LOGGER.info("ContentType: " + response.getHeader("ContentType"));
response.flushBuffer();
} catch (RequestFailureException | RESTAPIException | InvalidDataException | UnLoginException
| UnAuthorizedOperationException | IOException | Docx4JException | URISyntaxException e) {
e.printStackTrace();
}
}
}
And here are logs I got, you can see that Header "Content-Disposition" and "ContentType" are both null.
2014-05-07_13:35:05.646 INFO c.c.p.a.w.w.ImportExportController - exportedFileName: exportedTC_DEFAULT_JIRA_Test_CPL5_4520.docx
2014-05-07_13:35:05.646 INFO c.c.p.a.w.w.ImportExportController - contains: false
2014-05-07_13:35:05.646 INFO c.c.p.a.w.w.ImportExportController - Header: X-Content-Type-Options
2014-05-07_13:35:05.646 INFO c.c.p.a.w.w.ImportExportController - Header: X-XSS-Protection
2014-05-07_13:35:05.646 INFO c.c.p.a.w.w.ImportExportController - Header: Cache-Control
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Header: Pragma
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Header: Expires
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Header: X-Frame-Options
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Header: X-Application-Context
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Header: Transfer-Encoding
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Header: Date
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Date Header:Wed, 07 May 2014 17:35:05 GMT
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - Content-Disposition header: null
2014-05-07_13:35:05.647 INFO c.c.p.a.w.w.ImportExportController - ContentType: null
Thanks for reading. Any help will be appreciated.
Solution
It turns out to be Spring Controller have default header for all the responses so that I have access to the response body but not the headers. To set the HttpHeaders, return a HttpEntity will work. Solution code below:
@RequestMapping(value = "/export", method = RequestMethod.GET, produces = "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
public HttpEntity<byte[]> export(@RequestParam(value = "domainName", required = true) String domainName,
@RequestParam(value = "projectName", required = true) String projectName,
@RequestParam(value = "testFolderId", required = true) int testFolderId) {
String exportedFileName = "exportedTC_" + domainName + "_" + projectName + "_"
+ Integer.toString(testFolderId) + ".docx";
SaveToZipFile saver = null;
ByteArrayOutputStream out = null;
HttpHeaders responseHeaders = null;
byte[] documentBody = null;
try {
extendExpiredALMSession();
saver = wordProcessor.ExportToWord(domainName, projectName, Integer.toString(testFolderId));
out = new ByteArrayOutputStream();
saver.save(out);
responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document");
responseHeaders.add("Content-Disposition", "attachment; filename=\"" + exportedFileName + "\"");
documentBody = out.toByteArray();
} catch (RequestFailureException | RESTAPIException | InvalidDataException | UnLoginException
| UnAuthorizedOperationException | IOException | Docx4JException | URISyntaxException e) {
e.printStackTrace();
}
return new HttpEntity<byte[]>(documentBody, responseHeaders);
}
This works for me.
Answered By - David Z.
Answer Checked By - Timothy Miller (JavaFixing Admin)