8

In my @ActionMapping I create a PDF file for the user. Now I was wondering how I can return this pdf to the user in the form of a save/open file dialog box? I'd prefer this over showing a download link if the generation was succesful.

I'm using spring-mvc 3.0.5 in combination with portlets. But if anyone has some pointers for a normal application then I can probably figure it out from there. For 2.0 I read something about extending a pdfgenerator class and twidling in the web.xml but since nowadays we just need POJO's....


Edit: Code after Adeel's suggestion:

File file = new File("C:\\test.pdf");
        response.setContentType("application/pdf");

        try {
            byte[] b = new byte[(int) file.length()];
            OutputStream out = response.getPortletOutputStream();
            out.write(new FileInputStream(file).read(b));
            out.flush();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "users/main";
Mark Chorley
  • 2,087
  • 2
  • 22
  • 29
jack
  • 1,902
  • 5
  • 32
  • 43

4 Answers4

8

You can write that file directly to your response writer, and don't forget to change the contentType. For example,

response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment;filename=something.pdf");
OutputStream out = response.getOutputStream();
out.write(pdfFileContentInBytes);
out.flush();                   

Well, I thought its a HttpServletResponse what you have, but its not the case. As you are working with Portlet, its a RenderResponse object. After searching over the Internet, I found few links which might be helpful to you in this regard.

  • First take an example of Lotus Form Server Portlet, its showing the way how to allow multiple mime-type while configuring the portlet using portlet.xml.

  • Here is Spring Portlet docs, its showing how we configure portlet using portlet.xml. It has an XML element about mime-type, see if you can give the value, application/pdf, there.

Another idea is to change your parameter to ActionResponse response, instead of RenderResponse response. I am a bit blur here, not sure what is your super class? what method is it? etc....

To me, it seems that the problem is allowed/not-allowed mime-types for the portlet response.

Adeel Ansari
  • 39,541
  • 12
  • 93
  • 133
  • to add to Adeel's answer ..content type should be application/pdf – Mahesh Jan 04 '11 at 10:47
  • @Mahesh: I was just doing that :). Thanks anyway. – Adeel Ansari Jan 04 '11 at 10:50
  • Just tried that and I get: application/pdf is not a supported mime/type. But that seems to be in the right direction. – jack Jan 04 '11 at 14:49
  • @Jack: Surprising! It is a valid mime type. Check this out, http://tools.ietf.org/html/rfc3778. However, try with `application/octet-stream` this should work. But I would still suggest to troubleshoot why the former is giving you error. We might be able to say something, if you share the actual code and error message, both. – Adeel Ansari Jan 04 '11 at 15:00
  • Added some code. I'm using spring-portlet-mvc so I don't have direct access to a HttpServletResponse (needed for the setHeader since RenderResponse lacks that function (probably for a reason). And that was the actual error. application/pdf is not a supported mime type. – jack Jan 04 '11 at 15:09
  • Mmh, just tried that application/octet-stream and I get ERROR [jsp:154] java.lang.IllegalArgumentException: application/octet-stream is not a supported mime type. So unless that setHeader is required there's something deeper going on. – jack Jan 04 '11 at 15:17
  • @Jack: See if this thread, http://www.ibm.com/developerworks/forums/thread.jspa?threadID=264854, yields some idea/insight. Its a Websphere Portlet stuff there, BTW. – Adeel Ansari Jan 04 '11 at 16:23
  • Adeel, the parent class is just Object. Just like with spring-web-mvc you just annotate a POJO to use it as a spring-portlet-mvc controller. ActionResponse and RenderResponse are just different stages. You may (not must) have an action before a render. Action is actually an action while a RenderMapping has to do with the display. I'll give those extra mime types a try when I get an opportunity. (bit swamped currently) – jack Jan 04 '11 at 18:07
  • just gave it a try adding the extra mime types doesn't seem to have done the trick. I'll see if I can't find some time tomorrow evening to experiment a bit further with it. – jack Jan 04 '11 at 18:32
  • When I find a way to do this I'll update this post. But it seems it isn't possible to do this using a portlet. (Which is a bit logical since a portlet is part of the page, not the whole page and thus has limited capabilities. But it would have been nice to find a way. – jack Jan 07 '11 at 08:53
  • @Jack: See the first answer here, it is throwing some light, http://stackoverflow.com/questions/2361765/problem-to-display-a-pdf-from-my-jsf-portlet-of-liferay – Adeel Ansari Jan 07 '11 at 10:11
  • The solution is to use Resource Service Mechanism if you are using JSR 286 or configure a servlet if you are going with JSR 168 Portlets. See my answer for both the solutions. – Ashok Goli Jan 24 '12 at 19:54
4

in spring mvc, ResourceResponse response

response.reset();
response.setContentType("application/pdf");
response.setProperty("Content-disposition", "attachment; filename=\"" +"example.pdf" +"\"");

InputStream fontInputStream = request.getPortletSession()
                .getPortletContext()
                .getResourceAsStream("/WEB-INF/classes/arial.ttf");
Document document = new Document(PageSize.A4, 40, 40, 40, 50);
PdfWriter writer = PdfWriter.getInstance(document,
response.getPortletOutputStream());
document.addAuthor("XYZ");
document.addTitle("ASDF");
document.open();
PeterR
  • 183
  • 2
  • 17
1

Here's the answer after I worked it out for a little while: Serve PDF in Spring Portlet MVC Architecture - Liferay 6.0.6

The solution is to use Resource Serving Mechanism from JSR 286. The ResourceResponse res has a res.setContentType("application/pdf"); method so you can use it to serve any type of resources. If you need it to be downloaded as an attachment, then use this:

res.addProperty(HttpHeaders.CONTENT_DISPOSITION,"attachment");

Community
  • 1
  • 1
Ashok Goli
  • 5,043
  • 8
  • 38
  • 68
0

My code:

ResourceMapping("getPDF")

public void descargarRecibo(ResourceRequest request,
        ResourceResponse response, PortletSession session,
        ModelMap modelMap) {
    FileInputStream fileInputStream = null;
    BufferedInputStream bufferedInputStream = null;

    String fileURL = "c:/intranetdoc/PDetalleLlamadas/file.pdf";

    try {
        fileInputStream = new java.io.FileInputStream(fileURL);
        OutputStream outputStream = response.getPortletOutputStream();
        response.setContentType("application/pdf");
        response.addProperty("Content-Disposition", "attachment; filename="
                + fileName);
        bufferedInputStream = new java.io.BufferedInputStream(
                fileInputStream);
        byte[] bytes = new byte[bufferedInputStream.available()];
        response.setContentLength(bytes.length);
        int aByte = 0;
        while ((aByte = bufferedInputStream.read()) != -1) {
            outputStream.write(aByte);
        }
        outputStream.flush();
        bufferedInputStream.close();
        response.flushBuffer();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
java_xof
  • 439
  • 4
  • 16