TL;DR How can I download a file from my server using java portlet ResourceRequest?
I am building what is essentially a browser for our CMS with a Liferay 6.1.0 portlet using the GenericPortlet class. In the view.jsp, once a user has opened a CMS resource and if the resource (an HTML page) has links to PDFs or images, these links would trigger the following code to request the resource to be downloaded (to mimic normal behavior):
view.jsp
<portlet:resourceURL var="ajaxResourceUrl"/>
$("#file-viewer").on("click", "a", function(e){
/* Prevent normal link navigation behavior*/
e.preventDefault();
/* Get the name of the file we want to download*/
var linkPath = $(this).attr("href");
/* Send the path to the server with resource request*/
$.ajax({
method: 'POST',
url: '<%= ajaxResourceUrl %>',
data: {"action": "displayAttachment", "attachment": linkPath },
dataType: "text",
success: function(data) {
console.log("success:" + data.substring(0, 10));
if(data !== ""){
if(linkPath.substring(linkPath.length - 4, linkPath.length) === ".pdf"){
/* Resource is a PDF */
} else {
/* Resource is HTML */
var html = data;
var uri = "data:text/html," + encodeURIComponent(html);
var newWindow = window.open(uri);
}
} else {
$("#file-viewer").html("Error retrieving attachment \n" + $("#file-viewer").html());
}
},
error: function(err) {
console.log("error" + err);
}
});
});
Which is handled by this method on the server:
CMSBrowser.java
public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
String action = request.getParameter("action");
// handler for multiple ajax actions
if (new String("displayItem").equals(action)) {
//other irrelevant code
} else if (new String("displayAttachment").equals(action)) {
String filePath = request.getParameter("attachment");
PortletPreferences portletPreferences = request.getPreferences();
String rootPath = portletPreferences.getValue("rootPath", "");
filePath = rootPath + filePath;
try {
File f = new File(filePath);
System.out.println("Trying to serve: " + filePath);
String mimeType = request.getPortletSession().getPortletContext().getMimeType(f.getName());
response.setContentType(mimeType);
response.addProperty(
HttpHeaders.CACHE_CONTROL, "max-age=3600, must-revalidate");
OutputStream out = response.getPortletOutputStream();
InputStream in = new FileInputStream(f); // some InputStream
byte[] buffer = new byte[4096];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.flush();
in.close();
out.close();
} catch (IOException e) {
_log.error("serveResource: Unable to write IO stream, IOException: ", e);
}
}
}
I am not receiving any errors in Eclipse, in my browser, or in my server logs. Nothing happens except the ajax success method returns the "Error retrieving attachment" in case nothing is returned from the server.
I found the java code here as per the 4th post.
Specifically, I am trying to use this to download/open in a new tab PDFs and images that are on the server but not in the portlet/portal or otherwise accessible on the web. This method works with HTML pages.
My question is how can I download a file from my server using java portlet ResourceRequest?
(If there are mismatched closing parentheses, or curly braces please ignore this, I had to cut out a significant amount of code to post this here; everything lines up and closes correctly in my IDE).
After several attempts with similar solutions I tried removing the AJAX function in view.jsp and replaced it with this:
window.open('<%= ajaxResourceUrl %>&action=displayAttachment&attachment=' + linkPath);
This (somehow) worked and it now allows me to open HTML, PDFs, and images in a new tab.