Download PDF or JPG from portlet

To create a Download PDF link or serve images in your portlet, you need to implement serveResource method in your Liferay portlet class. Here’s an example on how to serve a JPG file from the server.

First we need to define a link to our file, this can be done using portlet taglib resourceURL like this.

<portlet:resourceURL var="niceImageUrl">
	<portlet:param name="fileName" value="flowers.jpg" />
</portlet:resourceURL>
<img src="<%= niceImageUrl %>" alt="flowers.jpg" />

Please note that you need to have portlet taglib in your JSP file header.

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

This generates a resource URL, so now we must implement the serveResource method to handle this call.

public class ImagesPortlet extends MVCPortlet {

	@Override
	public void serveResource(ResourceRequest request, ResourceResponse response)
			throws IOException, PortletException {

		String fileName = ParamUtil.getString(request, "fileName");

		File outputFile = new File("/Folder/On/Server/"+fileName);

		response.setContentType("image/jpg");
		OutputStream out = response.getPortletOutputStream();
		InputStream in = new FileInputStream(outputFile);
		IOUtils.copy(in, out);
		out.flush();
	}	
}

For PDF files you could easily tune it to have a link to your PDF like this:

<portlet:resourceURL var="pdfDownloadUrl">
	<portlet:param name="fileName" value="document.pdf" />
</portlet:resourceURL>
<a href="<%= pdfDownloadUrl %>">Download PDF</a>

And in the portlet class you can use code like this

public class PDFPortlet extends MVCPortlet {

	@Override
	public void serveResource(ResourceRequest request, ResourceResponse response)
			throws IOException, PortletException {

		String fileName = ParamUtil.getString(request, "fileName");

		File outputFile = new File("/Folder/On/Server/"+fileName);

		response.setContentType("application/pdf");
		OutputStream out = response.getPortletOutputStream();
		InputStream in = new FileInputStream(outputFile);
		IOUtils.copy(in, out);
		out.flush();
	}	
}

It’s important to use application/pdf content type so that the browser would know how to properly handle the file.

If you need to output multiple file types or handle different actions then you can pass an extra parameter that decides what file type to serve. Another idea could be to use a parameter to decide between serving a file or serving a JSON response, in case you need need to retrieve some data using AJAX. Here’s a simple example on how to pass content type in the URL to use it during serving the file.

<portlet:resourceURL var="pdfDownloadUrl">
	<portlet:param name="type" value="application/pdf" />
	<portlet:param name="fileName" value="document.pdf" />
</portlet:resourceURL>
<a href="<%= pdfDownloadUrl %>">Download PDF</a>

<portlet:resourceURL var="niceImageUrl">
	<portlet:param name="type" value="image/jpg />
	<portlet:param name="fileName" value="flowers.jpg" />
</portlet:resourceURL>
<img src="<%= niceImageUrl %>" alt="flowers.jpg" />

And in the portlet class you can just output the provided content type without having to detect it during download time. This allows you to define the expected content types dynamically, which can be very useful when you are generating a file list.

public class FilesPortlet extends MVCPortlet {

	@Override
	public void serveResource(ResourceRequest request, ResourceResponse response)
			throws IOException, PortletException {

		String type = ParamUtil.getString(request, "type");
		String fileName = ParamUtil.getString(request, "fileName");

		File outputFile = new File("/Folder/On/Server/"+fileName);

		response.setContentType( type );
		OutputStream out = response.getPortletOutputStream();
		InputStream in = new FileInputStream(outputFile);
		IOUtils.copy(in, out);
		out.flush();
	}	
}

More info on how to generate PDF on the fly can be read in this useful blog post.

As always, free feel to ask questions and provide suggestions in the comments.

About Reigo Reinmets

Enterprise Software consultant with 9 years of experience in enterprise software world who’s working on various projects that are mostly based on Liferay. Most blog posts here are real-life findings and issues we’ve encountered while working on projects and Java tutorials on Liferay.

2 thoughts on “Download PDF or JPG from portlet

Leave a Reply

Your email address will not be published. Required fields are marked *