Announcement Announcement Module
Collapse
No announcement yet.
Spring Web Flow + PDF Generation Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Web Flow + PDF Generation

    Hey all! I've spent the last 3 hours trying to get a view to generate a PDF file and then send it to the client and, to put it mildly, I've had no luck at all.

    I've been searching through the forums and since the word "pdf" doesn't get included due to min. length, I didn't have much luck.

    Can anyone point me in the right direction? Or even better, guide me through it? So far I know I have to subclass AbstractPdfView and use iText, but I have no idea how to output the PDF itself.


    Thanks!

  • #2
    Create a report flow:
    Code:
    <view-state id="report.view" view="externalRedirect:http://.....etc/report.htm?reportViewId=userPdfView">		
      <transition to="report.end"/>
    </view-state>
    
    <end-state id="report.end" />
    Setup your MVC Stuff using

    Code:
    .
      <prop key="/report.htm">reportController</prop>
    .
    
    <bean id="reportController" class="com.abc.web.controller.ReportController">
    	<property name="methodNameResolver" ref="methodNameResolver"/>		
    </bean>
    
    <bean id="methodNameResolver"
    		class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver" />
    		
    <bean id="viewResolver"	class="org.springframework.web.servlet.view.BeanNameViewResolver" />
    ReportController returns report view
    Code:
    public ModelAndView report(HttpServletRequest request, HttpServletResponse response) throws Exception {
      .
      return new ModelAndView(reportViewId);					}
    Report Mapping (UserPdfView extends Springs AbstractPdfView)
    Code:
    <bean id="userPdfView" class="com.abc.view.UserPdfView" />
    Hope that helps..

    Comment


    • #3
      See here for an example on building the pdf document:
      From Google Code Search

      Comment


      • #4
        Thanks! Much appreciated.

        Does the PDF View *have* to be an end-state?

        Comment


        • #5
          I don't follow you?

          The report.end transition just returns the flow to the parent.

          Comment


          • #6
            Gotcha. Slight newbie question: I'm using the standard architecture from the phonebook sample (started from that, then modified a lot...)

            Where does the "<prop key="/report.htm">reportController</prop>" bit go? Apologies.



            B

            Comment


            • #7
              snippet from SimpleUrlHandlerMapping

              Comment


              • #8
                After adding the snippets you posted, I now have 2 viewResolvers:
                Code:
                    <bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                
                    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                        <property name="prefix" value="/WEB-INF/jspx/"/>
                        <property name="suffix" value=".jspx"/>
                    </bean>
                What should I change?

                Comment


                • #9
                  Thank you jamesclinton. It works fine but I have a problem with the last nightly build. I have a link in a page which opens a pdf file with indicated method (externalRedirect). The file is well opened but the flow seems reinitialized. I have to click 2 times (the page is refreshed the first time) in the other link after having clicked on pdf link.

                  Comment


                  • #10
                    I have a redirection to an other flow which generates pdf (in the response) but main flow is reinitialized when I click on any link in the page. Why is the main flow reinitialized whereas the pdf is generated in other flow ?
                    I have not this behavior with the 2.0.0 ci-418 version.

                    Comment


                    • #11
                      Webflow 2.0.0.RELEASE

                      Hi,

                      With 2.0.0.RELEASE, It may not possible to write in the outputstream of response (which is accessible with requestcontext) in "evaluate expression".
                      With RC1, it was still possible to write in the outputstream of response and generate pdf.
                      Is there an equivalent of null view in viewstate (webflow 1.0.0) with webflow 2.0.0?
                      There is an other solution as jamesclinton describes is to use an other controller, but objects of webflow scope (conversation, flow) are not accessible.
                      Is there a solution for accessing objects in the flow scope outside flowController?

                      Thanks in advance

                      Comment


                      • #12
                        Originally posted by efshaolin View Post
                        Hi,
                        Is there a solution for accessing objects in the flow scope outside flowController?
                        If you in the flow, you can pop what you need in the http session. Then via the MVC controller extract it to build your doc.

                        Comment


                        • #13
                          write byte [] to PDF using spring web flow

                          Hi All,

                          We are developing an application using spring web flow. My requirement is to first generate PDF and store in the database (BLOB) in byte[]. Now i wanted to display PDF using stored byte[]. To generate PDF and get byte[] i am using Jasper API.

                          I searched using google however i did not find any Jasper API which generate PDF file using byte[]. I also took a look at the AbstarctPdfView, however we cannot pass byte[] to Document Object.

                          Can anybody help me how do i achieve this?

                          Comment


                          • #14
                            Originally posted by babybaby409 View Post
                            Hi All,

                            We are developing an application using spring web flow. My requirement is to first generate PDF and store in the database (BLOB) in byte[]. Now i wanted to display PDF using stored byte[]. To generate PDF and get byte[] i am using Jasper API.

                            I searched using google however i did not find any Jasper API which generate PDF file using byte[]. I also took a look at the AbstarctPdfView, however we cannot pass byte[] to Document Object.

                            Can anybody help me how do i achieve this?
                            See thread view-state on-render for download action for details on rendering a PDF. The solution I'm using is in post #6.

                            As for retrieving a PDF from a database Blob, you can try something like this...

                            PdfUtil.java
                            Code:
                                private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 4096;
                            
                                public static OutputStream convertInputStreamToOutputStream(InputStream inputStream)
                                    throws IOException {
                                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
                            
                                    // convert InputStream to OutputStream
                                    byte[] byteArray = new byte[OUTPUT_BYTE_ARRAY_INITIAL_SIZE];
                                    int bytesRead = 0;
                                    int offset = 0;
                            
                                    bytesRead = inputStream.read(byteArray, offset, OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
                            
                                    while (bytesRead != -1) {
                                        outputStream.write(byteArray, offset, bytesRead);
                                        bytesRead = inputStream.read(byteArray, offset, OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
                                    }
                            
                                    return outputStream;
                                }
                            ReportPdfServiceImpl.java
                            Code:
                                @Resource
                                private ReportPdfDao reportPdfDao;
                            
                                public OutputStream fetchReportPdf(Integer reportId)
                                    throws ApplicationException {
                                    try {
                                        return PdfUtil.convertInputStreamToOutputStream(reportPdfDao.fetchReportPdf(reportId));
                                    } catch (DataAccessException e) {
                                        throw new ApplicationException("fetch report pdf failed", e).code(ReportPdfServiceService.PDF_NOT_FOUND);
                                    } catch (SQLException e) {
                                        throw new ApplicationException("fetch report pdf failed", e).code(ReportPdfServiceService.PDF_NOT_FOUND);
                                    } catch (IOException e) {
                                        throw new ApplicationException("InputStream/OutputStream conversion failed in fetch report pdf ", e);
                                    }
                                }

                            JdbcReportPdfDao.java
                            Code:
                                private JdbcTemplate reportPdfJdbcTemplate = new JdbcTemplate(getDataSource());
                            
                                public InputStream fetchReportPdf(Integer reportId)
                                    throws DataAccessException, SQLException {
                                    Blob pdfBlob = null;
                                    InputStream pdf = null;
                            
                                    Map paramMap = new HashedMap();
                                    paramMap.put("reportId", reportId);
                            
                                    SqlParameterSource namedParameters = new MapSqlParameterSource(paramMap);
                            
                                    pdfBlob = (Blob) reportPdfJdbcTemplate.queryForObject(JdbcReportPdfDao.REPORT_PDF_BY_ID_SQL,
                                            namedParameters, Blob.class);
                            
                                    if (null != pdfBlob) {
                                        pdf = pdfBlob.getBinaryStream();
                                    }
                            
                                    return pdf;
                                }

                            Comment


                            • #15
                              Combining ResourceBundleViewResolver for jasper and otherwise UrlBasedViewResolver

                              Hey I'm trying something similar with the swf-booking-faces sample bundled in the swf 2.0.5 dist

                              I've added the controller

                              Code:
                              package org.springframework.webflow.samples.jasper;
                              
                              import java.util.HashMap;
                              import java.util.List;
                              import java.util.Map;
                              
                              
                              import org.springframework.web.servlet.ModelAndView;
                              import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
                              import org.springframework.webflow.samples.booking.Hotel;
                              
                              import org.springframework.stereotype.Service;
                              import java.io.Serializable;
                              
                              //I made my controller and modelAndView serializable to use it in the flow...
                              
                              @Service
                              public class ReportController extends MultiActionController implements Serializable   {
                              
                                      private static final long serialVersionUID = 1L;
                              
                              	public ModelAndView handleSimpleReport(List<Hotel> hotels) throws Exception {
                                          System.out.println("handleSimpleReport()");
                                          //Map mpHotels = (Map)hotels;
                              		return new SwfModelAndView("simpleReport", getModel(hotels));
                              	}
                              	
                              	private Map getModel(List<Hotel> hotels) {
                                          System.out.println("getModel");
                              		Map model = new HashMap();
                              		model.put("ReportTitle", "Dear Lord!");
                              		model.put("datasource", hotels);
                              
                              
                              		return model;
                              	}
                              	
                              }
                              and extended the ModelAndView (probably didn't need to,however..)

                              Code:
                              package org.springframework.webflow.samples.jasper;
                              
                              import java.io.Serializable;
                              import java.util.Map;
                              import org.springframework.web.servlet.ModelAndView;
                              
                              
                              public class SwfModelAndView extends ModelAndView implements Serializable {
                                      private static final long serialVersionUID = 1L;
                              
                                  public SwfModelAndView(String viewName,Map model){}
                              
                              }
                              in views.properties..

                              Code:
                              simpleReport.class=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
                              simpleReport.url=/WEB-INF/reports/report2.jasper
                              simpleReport.reportDataKey=datasource
                              but I have concluded that my problem resides in reolving my views..

                              in webmvc-config.xml I need the views to go to ResourceBundleViewResolver for jasper and otherwise toUrlBasedViewResolver...

                              but how to do this?

                              it will always resolve to /WEB-INF/simpleReport.xhtml when I want it to go to the views.properties file to lookup the file


                              see the configs below..



                              Code:
                              <!-- Maps request paths to flows in the flowRegistry; e.g. a path of /hotels/booking looks for a flow with id "hotels/booking" -->
                              	<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
                              		<property name="flowRegistry" ref="flowRegistry" />
                              		<property name="defaultHandler">
                              			<!-- If no flow match, map path to a view to render; e.g. the "/intro" path would map to the view named "intro" -->	
                              			<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
                              		</property>
                              	</bean>
                              
                              	<!-- Maps logical view names to Facelet templates in /WEB-INF (e.g. 'search' to '/WEB-INF/search.xhtml' -->
                              	<bean id="faceletsViewResolver" class="org.springframework.web.servlet.view.c">
                              		<property name="viewClass" value="org.springframework.faces.mvc.JsfView"/>
                              		<property name="prefix" value="/WEB-INF/" />
                              		<property name="suffix" value=".xhtml" />
                                              <property name="order"><value>1</value></property>
                              	</bean>
                              
                                  <!-- <bean id="pdfViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
                              		<property name="viewClass" value="org.springframework.webflow.samples.util.PdfPage"/>
                              		<property name="prefix" value="/WEB-INF/" />
                              		<property name="suffix" value=".pdf" />
                              	</bean> -->
                              
                                  <!-- the ResourceBundleViewResolver -->
                                  <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
                                    <property name="basename" value="views"/>
                                    <property name="order"><value>0</value></property>
                                  </bean>
                              
                              	<!-- Dispatches requests mapped to org.springframework.web.servlet.mvc.Controller implementations -->
                              	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
                              
                              	<!-- Dispatches requests mapped to flows to FlowHandler implementations -->
                              	<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
                              		<property name="flowExecutor" ref="flowExecutor" />
                              	</bean>
                              (see subflow below...)

                              Code:
                              <var name="reportController" class="org.springframework.webflow.samples.jasper.ReportController" />
                              		        <var name="modelAndView" class="org.springframework.web.servlet.ModelAndView" />
                              			<input name="hotels" required="true" type="dataModel" />
                              		        <input name="searchCriteria" required="true" />
                              		
                              		        <on-start>
                              		            <evaluate expression="bookingService.addMsg('now in subflow...')" />
                              		            <evaluate expression="reportController.handleSimpleReport(bookingService.findHotels(searchCriteria,externalContext.locale))"  result="flowScope.modelAndView" />
                              		        </on-start>
                              		        <view-state id="simpleReport" popup="true">
                              		
                              		            <on-entry>
                              		                <evaluate expression="bookingService.addMsg('entered view-state displayPdfState')" />
                              		            </on-entry>
                                      		</view-state>



                              So I do get the following output msgs from my flow that calls the controller..

                              handleSimpleReport() and getModel so i know the modelAndView is returned

                              yet...

                              Code:
                              2009-09-20 22:47:21,568 DEBUG [org.springframework.webflow.engine.Flow] - <Restoring [FlowVariable@1ea01711 name = 'reportController', valueFactory = [BeanFactoryVariableValueFactory@204a6ccc type = ReportController]]>
                              	2009-09-20 22:47:21,568 DEBUG [org.springframework.webflow.engine.Flow] - <Restoring [FlowVariable@2ff1bf46 name = 'modelAndView', valueFactory = [BeanFactoryVariableValueFactory@2844a541 type = ModelAndView]]>
                              	2009-09-20 22:47:21,677 DEBUG [org.springframework.faces.webflow.FlowViewStateManager] - <No matching view in view scope>
                              	2009-09-20 22:47:21,677 DEBUG [org.springframework.faces.webflow.JsfViewFactory] - <Creating UIViewRoot from 'simpleReport.xhtml'>
                              	2009-09-20 22:47:21,677 DEBUG [org.springframework.webflow.engine.ViewState] - <Rendering + [JSFView = '/WEB-INF/flows/pdfHotels/simpleReport.xhtml']>
                              	2009-09-20 22:47:21,677 DEBUG [org.springframework.webflow.engine.ViewState] - <  Flash scope = map['flowRenderResponse' -> true]>
                              	2009-09-20 22:47:21,786 DEBUG [org.springframework.webflow.engine.ViewState] - <  Messages = [DefaultMessageContext@708a605c sourceMessages = map[[null] -> list[[empty]]]]>
                              	2009-09-20 22:47:21,786 DEBUG [org.springframework.faces.support.RequestLoggingPhaseListener] - <Entering JSF Phase: RENDER_RESPONSE 6>
                              	2009-09-20 22:47:21,786 DEBUG [org.springframework.faces.webflow.JsfView] - <Asking view handler to render view>
                              	20-Sep-2009 10:47:21 PM com.sun.facelets.FaceletViewHandler handleRenderException
                              	SEVERE: Error Rendering View[/WEB-INF/flows/pdfHotels/simpleReport.xhtml]




                              In short how do I target the correct viewResolver for the right case, must be a solution out there !


                              Any suggestions as to what changes to make?

                              Has anyone succeeded in adding jasperreports to the swf-booking-faces example?

                              my best regards to all!

                              Kevin u out there?

                              Comment

                              Working...
                              X