spring-mvc (portlet): how to return a pdf file in open file dialog?
Asked Answered
H

4

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";
Higgler answered 4/1, 2011 at 10:43 Comment(0)
P
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.

Papeterie answered 4/1, 2011 at 10:45 Comment(12)
to add to Adeel's answer ..content type should be application/pdfAdis
@Mahesh: I was just doing that :). Thanks anyway.Papeterie
Just tried that and I get: application/pdf is not a supported mime/type. But that seems to be in the right direction.Higgler
@Jack: Surprising! It is a valid mime type. Check this out, 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.Papeterie
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.Higgler
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.Higgler
@Jack: See if this thread, ibm.com/developerworks/forums/thread.jspa?threadID=264854, yields some idea/insight. Its a Websphere Portlet stuff there, BTW.Papeterie
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)Higgler
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.Higgler
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.Higgler
@Jack: See the first answer here, it is throwing some light, #2362265Papeterie
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.Turtleback
B
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();
Bakke answered 21/6, 2011 at 12:6 Comment(1)
setProperty() as a replacement for setHeader() in portlets - Good to know that this will workTrotta
T
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");

Turtleback answered 24/1, 2012 at 19:51 Comment(0)
T
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();
    }
}
Tadtada answered 24/1, 2013 at 22:11 Comment(1)
lol - sorry - thought that was a question - however few words of introduction would be niceHeadband

© 2022 - 2024 — McMap. All rights reserved.