You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
| Online: | 25 Members of 4546 |
| Forum: Seam Users |
06. Mar 2008, 12:15 CET | Link |
Hi,
i have created a pdf with itext directly in my action class and iText is offering me some outputstream options (e.g. ByteArrayOutputStream, ...)
Now i would like to send this pdf (stream) to a browser without using a jsf (.xhtml) page. Or is there a tag to this ? I do not want to store the pdf on disc if i can avoid it.
Is this possible ?
Any ideas are welcome.
Best regards.
mki
Easy. Use the byteArrayOutputStream and hook it up to a servlet. You can keep the byteArrayOutputStream in memory in a conversation/session scoped Bean until the servlet needs it. Use Component.getInstance() in your servlet to access the Bean.
Cheers,
Damian.
mki,
Possibly an even easier way that doesn't require writing a custom servlet....write a Seam component that serves up the report - this is the approach we took for the application we demoed at JbossWorld.
@Name("reportAction") public class ReportAction { @In private FacesContext facesContext; public void run() { final HttpServletResponse resp = (HttpServletResponse) facesContext.getExternalContext().getResponse(); // run the report // write the report to resp.getOutputStream() facesContext.responseComplete(); } }Then in xhtml
<h:commandLink action="#{reportAction.run}"/>or
<s:link action="#{reportAction.run}"/>etc.
Good luck!
Thanks Keith,
that was exactly the solution i was looking for. :-)
Keith,
I gave this a go and it's very cool and easier to implement than the servlet. The only thing that escapes me at the moment is how to assign a filename to the download. With the servlet I used a servlet URL pattern so I could put any name in the link.
What is the JSF equivalent of that?
Cheers,
Damian.
That's easy, you simply have to set the Content-Disposition in the header:
final HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); response.setContentType("application/pdf"); response.setHeader("Content-Disposition", " attachment; filename=invoice.pdf");Greetings,
Manuel
Genius. Thanks Manuel & Keith. Much appreciated.
Cheers,
Damian.
Damian, Manuel has it dead on. If I remember correctly IE behaves slightly differently than the other browsers so you may or may not see the right filename in all browsers. I just found this article that describes IE's flakiness.
I would have replied sooner, but we just had a record snowfall of 16 inches and I've spent a good part of the day digging out of it!
Keith
I have used exactly that technique a couple of times, but recently I got notice from quite a few customers that it .
The problem was Safari (3+ something, whatever ships with their newest -release), where this approch does not work. So we also had to go with the custom servlet approach, which works fine.
I implemented the solution described by Keith Naas on 3/6, and it got it working. I'm just learning, so it took a little while. Now that I have it, I would like to expose the servlet so that it is available by direct URL, instead of by JSF commandLink. Is that possible? How would I go about doing that?
Speak good words, Think good thoughts, Walk a good road.
Ken,
you can define a link to your action in pages.xml.
<page view-id="/pdf.xhtml" action="#{pdfgeneratorAction.generate}"/>Manuel
Thanks Manuel. Is there a way to configure it so that the page I use (/pdf.xhtml in your example) doesn't actually have to exist? I can certainly put the page in place, but it seems sort of kludgy, since it never gets displayed, and never should.
Speak good words, Think good thoughts, Walk a good road.
Thanks for your help. I am new at this, so I'm certain I'm asking questions that would seem stupid to anyone who knows this stuff, but anyway, I have one more thing. I was hoping to pass form information in the request, and use that to manipulate the PDF created. After setting up access through pages.xml, I'm not seeing any parameters in the HttpServletRequest object. I promise I'm not trying to get you to write my code for me, but I'm up against the boundaries of my knowledge.
The HTML code that calls this looks like this:
My code looks like this, and I'm finding nothing in my parameterMap:
public class PrintServer extends SeamResourceServlet { private static final long serialVersionUID = 1278807414184735439L; @In private FacesContext facesContext; @Logger private static Log log; public void test( String message ) throws ServletException, IOException, DocumentException { final HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); final HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest(); log.info( "context path: " + request.getContextPath()); log.info( "method: " + request.getMethod()); log.info( "URI: " + request.getRequestURI()); Map parameterMap = request.getParameterMap(); if( parameterMap==null) { log.info( "Can't get parameter names"); } else { log.info("Request Parameters: " + parameterMap.toString()); Collection <Map.Entry> paramCollection = parameterMap.entrySet(); java.util.Iterator <Map.Entry> paramIterator = paramCollection.iterator(); while( paramIterator.hasNext()) { Map.Entry me = paramIterator.next(); String [] sa = (String [] ) me.getValue(); String sValue = ""; for( int i=0; i<sa.length; ++i ) { sValue += sa[i] + ","; } log.info("Request Parameter " + me.getKey() + " size " + sValue); } log.info("Request Parameters size: " + parameterMap.size()); } log.info("Request Querystring: " + request.getQueryString()); facesContext.responseComplete(); ServletOutputStream out = response.getOutputStream(); Document document = new Document(); PdfWriter.getInstance(document, out); document.open(); document.add(new Paragraph("Form message: " + message)); document.close(); response.setContentType("application/pdf"); response.setHeader("Content-Disposition", " attachment; filename=PrintTest.pdf"); log.info("Run GraphServer.test"); return; } }Speak good words, Think good thoughts, Walk a good road.
Ken,
the beauty of the solution in 3 is, that it does even not use a servlet to deliver the PDF, so you can do everything in a standard seam way by calling an action, create the pdf and deliver it to the browser.
Inside this action you have easy access to all form values.
So why going the hard way ?
Manuel
Thanks for your help Manuel.
Am I going the hard way? I thought I was replicating the solution above. I do see that my code extends the SeamResourceServlet, but I'm not using that interface - it was left over from my servlet approach, and I forgot to remove it.
I restarted my JBoss server (the whole machine, in fact) and now I'm seeing the form information. There must have been something left in my deployment that was interfering, and it got cleaned out by the restart. So the code I provided above works after all.
As a last question, is there a better/simpler way to retrieve the form information than what I do above?
Thanks again.
Speak good words, Think good thoughts, Walk a good road.
I have another question about this. If I use same aproach as above to show images stored in a database as a blob, how do I map the image url to this ActionClass (ReportAction).
Let's I want all my image urls to be: http://localhost:8080/project/images/foo.jpg
How do I do the mapping from the url so it's mapped to the ActionClass?
Thanks,
/Jacob
If I used a Custom servlet I would have to add this to the web.xml
<servlet> <servlet-name>CustromServlet</servlet-name> <servlet-class>test.CustomServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CustromServlet</servlet-name> <url-pattern>/image/*</url-pattern> </servlet-mapping>But the above aproach is not a servlet, how or is it possible? :)
/Jacob
You could try with pages.xml:
<page view-id="/image/*"> <!-- This is a dummy page - it don't exist ! --> <action execute="#{<component name>.<action method>}"/> ... ... </page>