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?
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?
blank jasper detail section
I'm stubbornly still at it!
Trying to create a jasperreport pdf view for the swf-booking-faces sample bundled in the swf 2.0.5 dist..
I can get it to produce the pdf however the detail section of the report is blank no matter what I try...
If I run this in the current netBeans with the sql (jdbc datasource) it runs OK and you can see eveything OK...
if I run this off the page <a href="simpleReport.pdf" >PDF</a> there's no error and the detail section is blank!
the relevant code is as follows...
the report2.jrxml (what's wrong with it?)
Code:
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="simpleReport" pageWidth="595" pageHeight="842" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" isFloatColumnFooter="true">
<property name="ireport.scriptlethandling" value="0"/>
<property name="ireport.encoding" value="UTF-8"/>
<import value="net.sf.jasperreports.engine.*"/>
<import value="java.util.*"/>
<import value="net.sf.jasperreports.engine.data.*"/>
<field name="id" class="java.lang.Long"/>
<field name="address" class="java.lang.String"/>
<field name="name" class="java.lang.String"/>
<background>
<band splitType="Stretch"/>
</background>
<title>
<band height="79" splitType="Stretch">
<staticText>
<reportElement x="173" y="17" width="224" height="31"/>
<textElement>
<font size="14" isBold="true"/>
</textElement>
<text><![CDATA[Why can't this work?]]></text>
</staticText>
</band>
</title>
<pageHeader>
<band height="35" splitType="Stretch"/>
</pageHeader>
<columnHeader>
<band height="61" splitType="Stretch">
<staticText>
<reportElement x="0" y="41" width="38" height="20"/>
<textElement/>
<text><![CDATA[ID]]></text>
</staticText>
<textField evaluationTime="Auto" pattern="" isBlankWhenNull="false">
<reportElement x="48" y="10" width="81" height="31"/>
<textElement>
<font fontName="Verdana"/>
</textElement>
<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="155" y="10" width="107" height="31"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{address}]]></textFieldExpression>
</textField>
</band>
</columnHeader>
<detail>
<band height="57" splitType="Stretch">
<textField pattern="" isBlankWhenNull="false">
<reportElement x="0" y="0" width="38" height="31"/>
<textElement/>
<textFieldExpression class="java.lang.Long"><![CDATA[$F{id}]]></textFieldExpression>
</textField>
<textField pattern="" isBlankWhenNull="false">
<reportElement key="textField" positionType="Float" mode="Transparent" x="38" y="0" width="81" height="31" forecolor="#000000"/>
<textElement>
<font fontName="Verdana"/>
</textElement>
<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="119" y="0" width="75" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{address}]]></textFieldExpression>
</textField>
</band>
</detail>
<columnFooter>
<band height="45" splitType="Stretch"/>
</columnFooter>
<pageFooter>
<band height="54" splitType="Stretch">
<textField pattern="EEEEE dd MMMMM yyyy">
<reportElement x="0" y="34" width="173" height="20"/>
<textElement/>
<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
</textField>
<textField>
<reportElement x="426" y="34" width="80" height="20"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
</textField>
<textField evaluationTime="Report">
<reportElement x="506" y="34" width="40" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
</textField>
</band>
</pageFooter>
<summary>
<band height="42" splitType="Stretch"/>
</summary>
</jasperReport>
just to see if it gets the datasource in the modelAndView I output two $F{name} and $F{address} in the Column Header band and this
works leading me to believe the datasource is visible...
the controller...
Code:
package org.springframework.webflow.samples.jasper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.springframework.webflow.samples.booking.Hotel;
public class ReportControllerSvlt extends MultiActionController {
public ModelAndView handleSimpleReport(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out.println("ReportControllerSvlt.handleSimpleReport()");
return new ModelAndView("simpleReport", getModel());
}
private Map getModel() {
System.out.println("ReportControllerSvlt.getModel()");
Map<Object,Object> model = new HashMap<Object,Object>();
model.put("datasource", getData());
System.out.println("model="+model.toString());
return model;
}
private List getData() {
System.out.println("ReportControllerSvlt.getData()");
ArrayList<Hotel> list = new ArrayList<Hotel>();
for (int x = 0; x < 10; x++) {
Hotel hotel = new Hotel();
String strInt = ""+x;
hotel.setId(Long.parseLong(strInt));
hotel.setName("Rob Harrop");
if (x % 2 == 0) {
hotel.setCity("Deux mtgs");
hotel.setAddress("123 10ieme av");
}
else {
hotel.setCity("Pompano beach");
hotel.setAddress("top o world");
}
System.out.println("hotel="+hotel.toString());
list.add(hotel);
}
return list;
}
}
webmvc-config.xml...
Code:
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry" />
<property name="defaultHandler">
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
<bean id="faceletsViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<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" />
</bean>
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers">
<list>
<ref bean="controllerResolver" />
<ref bean="jasperViewResolver" />
<ref bean="faceletsViewResolver" />
</list>
</property>
</bean>
<bean id="jasperViewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename" value="views"/>
<property name="order" value="0" />
</bean>
<bean id="controllerResolver" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props merge="default">
<prop key="*.*">controller</prop>
</props>
</property>
<property name="order" value="0" />
</bean>
<bean id="controller" class="org.springframework.webflow.samples.jasper.ReportControllerSvlt" lazy-init="default" autowire="default" dependency-check="default">
<property name="methodNameResolver">
<ref local="resolver" />
</property>
</bean>
<bean id="resolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver" lazy-init="default" autowire="default" dependency-check="default">
<property name="mappings">
<props merge="default">
<prop key="/simpleReport.pdf">handleSimpleReport</prop>
</props>
</property>
</bean>
</beans>
views.properties...
Code:
simpleReport.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
simpleReport.url=/WEB-INF/reports/report2.jasper
simpleReport.reportDataKey=datasource
Why are the fields yielded in the ColumnHeader but not shown in the Details band ( nothing not even the expected Null is printed)??
Is there any way to get DEBUG msgs when u get the pdf from the jasper compilation?
Any help at all would be greatly appreciated, i've spent a great deal of time trying to figure this out.
Cheers to all!
Code:
<dead tired>John</dead tired>
swf-booking-faces jasper reports
I guess I should elaborate on the situation.
I'm taking the swf-booking-faces sample bundled in the SWF distribution ver2.0.5 (a recent distr)
and getting the reviewHotels.xhtml to have a sf:commandLink that will print the Hotels searchResult (as a popup) using
jasperreports.
OK so I can produce the report.pdf to a folder on the classpath, no problem. But how could you open the view using webflow?
(I've tried many classpath locations, settled on
Code:
C:\NetBeansProjects\swf-booking-faces_sept18\src\main\webapp\reports\report.pdf
since that will open with
Code:
http://localhost:8084/swf-booking-faces/reports/report2.pdf
)
The only way I can open it is with:
Code:
<view-state id="report2.view" view="externalRedirect:/reports/report2.pdf">
but then I get the first cached version produced when the server started and the <view popup=true doesn't work
with externalRedirects.
It seems the only way to have the report work is with
Code:
<a href="simpleReport.pdf" target="_blank">Printable list</a>
that will only compile a hardcoded data ( via the JasperReportsPdfView class )with no interaction with current view (ie: you couldn't send the search criteria to the query).
There must be a way to produce the report in a flow that will have access to flow vars. If you separate the report to a controller with req/resp it won't interact with the flow and xhtml components,... leaves you cold!
I have managed to popup the report but it creates parse errors since it's a pdf file...
What to do?
Has anyone been able to open pdf jasperreports using the swf-booking-faces sample yet?
Regards,
John
P.S. tried everything, separate servlet etc, gets swallowed up/busted by the framework.