Spring Web MVC With Jasper Reports
Spring Web MVC With Jasper Reports
To do this tutorial quickly and easily, create a Tomcat project called springjasperreports in
the webapps folder of your Tomcat installation. I will show you a structure of all folders inside
the project (would change according your logic). At first glance it can be a little confusing but
later it will be easier to understand.
Step 2: Configuring web.xml
view source
print?
01.<display-name>springjasperreports</display-name>
02. <context-param>
03. <param-name>webAppRootKey</param-name>
04. <param-value>springjasperreports.root</param-value>
05. </context-param>
06. <session-config>
07. <session-timeout>60</session-timeout>
08. </session-config>
09. <context-param>
10. <param-name>contextConfigLocation</param-name>
11. <param-value>
12. /WEB-INF/springjasperreports-servlet.xml
13. /WEB-INF/xml/context/applicationContext-swf.xml
14. /WEB-INF/xml/context/applicationContext-jasperreports.xml
15. /WEB-INF/xml/context/applicationContext-
jasperreportsengine.xml
16. </param-value>
17. </context-param>
18.
19. <servlet>
20. <servlet-name>springjasperreports</servlet-name>
21. <servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
22. <init-param>
23. <param-name>detectAllViewResolvers</param-name>
24. <param-value>false</param-value>
25. </init-param>
26. </servlet>
27.
28. <listener>
29. <listener-
class>org.springframework.web.context.ContextLoaderListener</listener-class>
30. </listener>
31.
32. <servlet-mapping>
33. <servlet-name>springjasperreports</servlet-name>
34. <url-pattern>*.htm</url-pattern>
35. </servlet-mapping>
36.
37. <welcome-file-list>
38. <welcome-file>index.jsp</welcome-file>
39. </welcome-file-list>
40.
41. <taglib>
42. <taglib-uri>/spring</taglib-uri>
43. <taglib-location>/WEB-INF/spring.tld</taglib-location>
44. </taglib>
Step 3: Engine and Wrap Class
view source
print?
01.public class EngineSomeEntitiesJasperReport {
02.
03. public JRBeanCollectionDataSource engine(){
04.
05. WrapSomeEntities wrapSomeEntitiesOne = new WrapSomeEntities();
06. wrapSomeEntitiesOne.setIdCustomer("MJE-88");
07. wrapSomeEntitiesOne.setNameCustomer("Manuel Jordan");
08. wrapSomeEntitiesOne.setPhoneCustomer("222222");
09. wrapSomeEntitiesOne.setIdProvider("XYZ-123");
10. wrapSomeEntitiesOne.setNameProvider("Company A");
11. wrapSomeEntitiesOne.setPhoneProvider("457898");
12. wrapSomeEntitiesOne.setIsbn("1590599799");
13. wrapSomeEntitiesOne.setTitleBook("Spring Recipes");
14. wrapSomeEntitiesOne.setPriceBook(new BigDecimal("49.99"));
15.
16. WrapSomeEntities wrapSomeEntitiesTwo = new WrapSomeEntities();
17. wrapSomeEntitiesTwo.setIdCustomer("MJE-88");
18. wrapSomeEntitiesTwo.setNameCustomer("Manuel Jordan");
19. wrapSomeEntitiesTwo.setPhoneCustomer("222222");
20. wrapSomeEntitiesTwo.setIdProvider("XYZ-777");
21. wrapSomeEntitiesTwo.setNameProvider("Company B");
22. wrapSomeEntitiesTwo.setPhoneProvider("697451");
23. wrapSomeEntitiesTwo.setIsbn("020161622X");
24. wrapSomeEntitiesTwo.setTitleBook("The Pragmatic Programmer");
25. wrapSomeEntitiesTwo.setPriceBook(new BigDecimal("45.99"));
26.
27. List<WrapSomeEntities> myList = new ArrayList<WrapSomeEntities>();
28. myList.add(wrapSomeEntitiesOne);
29. myList.add(wrapSomeEntitiesTwo);
30.
31. JRBeanCollectionDataSource jRBeanCollectionDataSource = new
JRBeanCollectionDataSource(myList);
32. return jRBeanCollectionDataSource;
33. }
34.}
Dont Forget that our pojo WrapSomeEntities must contain all variables created like <field
name="......."/> in the *.jrxml file by the query done in IReport
view source
print?
01.public class EngineLineasArticulosJasperReport {
02.
03. private JdbcTemplate jdbcTemplate;
04.
05. public void setJdbcTemplate(DataSource dataSource) {
06. this.jdbcTemplate = new JdbcTemplate(dataSource);
07. }
08.
09. /**
10. * <p>
11. * Metodo que me llena y retorna el JRBeanCollectionDataSource
12. * </p>
13. *
14. * @return JRBeanCollectionDataSource
15. */
16. public JRBeanCollectionDataSource engine(){
17. String query=" SELECT *, a.descripcion as descripcionarticulo " +
18. " FROM lineacategoria l, articulo a, medida d WHERE " +
19. " l.idLineaCategoria = a.idLineaCategoria AND
a.idMedida=d.idMedida order by l.idLineaCategoria ";
20.
21. Collection mycollecion = this.jdbcTemplate.query(
22. query ,
23. new RowMapper() {
24. public Object mapRow(ResultSet rs, int rowNum) throws
SQLException {
25. WrapLineasArticulos a = new WrapLineasArticulos();
26.
27. a.setIdLineaCategoria(rs.getString("idLineaCatego
ria"));
28. a.setDescripcion(rs.getString("descripcion"));
29. a.setIdArticulo(rs.getString("idArticulo"));
30. a.setStockactual(rs.getBigDecimal("stockactual"));
31. a.setPrecioUnitario(rs.getBigDecimal("precioUnitario
"));
32. a.setPrecioUnitarioVenta(rs.getBigDecimal("precio
UnitarioVenta"));
33. a.setTotalValorizado(rs.getBigDecimal("totalValor
izado"));
34. a.setXtraTextUnoArticulo(rs.getString("xtraTextUnoAr
ticulo"));
35. a.setXtraNumDosArticulo(rs.getBigDecimal("xtraNumDo
sArticulo"));
36. a.setIdMedida(rs.getString("idMedida"));
37. a.setNombre(rs.getString("nombre"));
38. a.setDescripcionarticulo(rs.getString("descripcion
articulo"));
39. return a;
40. }
41. });
42.
43. JRBeanCollectionDataSource jRBeanCollectionDataSource = new
JRBeanCollectionDataSource(mycollecion);
44. return jRBeanCollectionDataSource;
45. }
46.
47.}
If you look carefully the sql statement, it works for related tables (Pk/Fk relation). Another
case could be for unrelated tables (working with JOIN clause). The rest of the code is obvious
view source
print?
01.public class WrapSomeEntities {
02.
03. private String idCustomer;
04. private String nameCustomer;
05. private String phoneCustomer;
06. private String idProvider;
07. private String nameProvider;
08. private String phoneProvider;
09. private String isbn;
10. private String titleBook;
11. private BigDecimal priceBook;
12.
13. public String getIdCustomer() {
14. return idCustomer;
15. }
16. public void setIdCustomer(String idCustomer) {
17. this.idCustomer = idCustomer;
18. }
19. public String getNameCustomer() {
20. return nameCustomer;
21. }
22. public void setNameCustomer(String nameCustomer) {
23. this.nameCustomer = nameCustomer;
24. }
25. public String getPhoneCustomer() {
26. return phoneCustomer;
27. }
28. public void setPhoneCustomer(String phoneCustomer) {
29. this.phoneCustomer = phoneCustomer;
30. }
31. public String getIdProvider() {
32. return idProvider;
33. }
34. public void setIdProvider(String idProvider) {
35. this.idProvider = idProvider;
36. }
37. public String getNameProvider() {
38. return nameProvider;
39. }
40. public void setNameProvider(String nameProvider) {
41. this.nameProvider = nameProvider;
42. }
43. public String getPhoneProvider() {
44. return phoneProvider;
45. }
46. public void setPhoneProvider(String phoneProvider) {
47. this.phoneProvider = phoneProvider;
48. }
49. public String getIsbn() {
50. return isbn;
51. }
52. public void setIsbn(String isbn) {
53. this.isbn = isbn;
54. }
55. public String getTitleBook() {
56. return titleBook;
57. }
58. public void setTitleBook(String titleBook) {
59. this.titleBook = titleBook;
60. }
61. public BigDecimal getPriceBook() {
62. return priceBook;
63. }
64. public void setPriceBook(BigDecimal priceBook) {
65. this.priceBook = priceBook;
66. }
67.
68.
69.}
Our EngineSomeEntitiesJasperReport must be declared in our Spring context. For this bean,
it is declared in applicationContext-jasperreportsengine.xml
view source
print?
1.<beans>
2.
3. <bean id="idEngineSomeEntitiesJasperReport"
4. class="com.springjasperreports.model.jasperreport.engine.EngineSom
eEntitiesJasperReport" />
5.
6.</beans>
We have done the Model Layer (for simplicity in this case the
EngineSomeEntitiesJasperReport class), now we must handle the controllers, so it's onto
Spring Web MVC.
We are using a setter method to inject our engine class; the handleRequestInternal method is
calling the engine method and receives the JRBeanCollectionDataSource object. For this
example no parameters are used (i.e request.getParameter(...)). An important part of the code is
parameterMap.put("datasource", jRBeanCollectionDataSource);
view source
print?
01.<beans>
02.
03. <bean id="idReportSimplePdfJasperReportController"
04. class="com.springjasperreports.controler.mvc.jasperreports.Report
SimplePdfJasperReportController" >
05. <property name="engineSomeEntitiesJasperReport" >
06. <ref bean="idEngineSomeEntitiesJasperReport" />
07. </property>
08. </bean>
09.
10.</beans>
To handle the actions we use Spring Web Flow. For that the
ReportSimplePdfJasperReportAction is created, see the code below
view source
print?
01.public class ReportSimplePdfJasperReportAction extends AbstractAction{
02.
03. private EngineSomeEntitiesJasperReport engineSomeEntitiesJasperReport;
04.
05. public void setEngineSomeEntitiesJasperReport(
06. EngineSomeEntitiesJasperReport engineSomeEntitiesJasperReport)
{
07. this.engineSomeEntitiesJasperReport =
engineSomeEntitiesJasperReport;
08. }
09.
10. protected Event doExecute(RequestContext context)throws Exception{
11. try{
12.
13. JRBeanCollectionDataSource jRBeanCollectionDataSource =
14. this.engineSomeEntitiesJasperReport.engine();
15.
16. context.getRequestScope().put("datasource",
jRBeanCollectionDataSource);
17. }
18. catch(Exception e){
19. }
20. return success();
21. }
22.}
Again we are using a setter method to inject our engine class; the doExecute method calls the
engine method and recieve the JRBeanCollectionDataSource object. For this example, again
no parameters are used (i.e context.getFlowScope().get(...)). An important part of the code is
context.getRequestScope().put("datasource", jRBeanCollectionDataSource);
Our ReportSimplePdfJasperReportAction must be declared like a bean too; but we are
working with SWF; then for this bean, it is declared in springwebflowjasperreports-
beans.xml
view source
print?
01.<beans xmlns="http://www.springframework.org/schema/beans"
02. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
03. xsi:schemaLocation="http://www.springframework.org/schema/beans
04. http://www.springframework.org/schema/beans/sp
ring-beans.xsd">
05.
06. <bean id="reportSimplePdfJasperReportAction"
07. class="com.springjasperreports.swf.actions.jasperreports.Re
portSimplePdfJasperReportAction" >
08. <property name="engineSomeEntitiesJasperReport" >
09. <ref bean="idEngineSomeEntitiesJasperReport" />
10. </property>
11. </bean>
12.</beans>
Now we must declare the states of our flow. Then for this flow, we will create
springwebflowjasperreports-flow.xml, and see the code below
view source
print?
01.<flow xmlns="http://www.springframework.org/schema/webflow"
02. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
03. xsi:schemaLocation="http://www.springframework.org/schema/webflow
04. http://www.springframework.org/schema/webflow/s
pring-webflow-1.0.xsd">
05.
06. <start-state idref="springwebflowjasperreports-one" />
07.
08. <view-state id="springwebflowjasperreports-one"
09. view="springwebflowjasperreports-stepone">
10. <transition on="next" to="springwebflowjasperreports-two" />
11. </view-state>
12.
13. <view-state id="springwebflowjasperreports-two"
14. view="springwebflowjasperreports-steptwo">
15. <transition on="next" to="springwebflowjasperreports-printpdf" />
16. <transition on="end" to="springwebflowjasperreports-end" />
17. </view-state>
18.
19. <view-state id="springwebflowjasperreports-printpdf"
20. view="reportsimplepdfjasperreport" >
21. <render-actions>
22. <action bean="reportSimplePdfJasperReportAction" />
23. </render-actions>
24. <!-- I am still using the last jsp of the flow -->
25. <transition on="next" to="springwebflowjasperreports-printpdf" />
26. <transition on="end" to="springwebflowjasperreports-end" />
27. </view-state>
28.
29. <end-state id="springwebflowjasperreports-end" view="welcome" >
30. </end-state>
31. <import resource="springwebflowjasperreports-beans.xml"/>
32.
33.</flow>
The states declaration is clear by itself. For a better idea, using Spring IDE we can see the flow
in a graphical way.
The last part with SWF is to create the configuration. For that, we will create
applicationContext-swf.xml
view source
print?
01.<beans xmlns="http://www.springframework.org/schema/beans"
02. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
03. xmlns:flow="http://www.springframework.org/schema/webflow-config"
04. xsi:schemaLocation="
05. http://www.springframework.org/schema/beans
06. http://www.springframework.org/schema/beans/spring-beans-
2.0.xsd
07. http://www.springframework.org/schema/webflow-config
08. http://www.springframework.org/schema/webflow-config/spring-
webflow-config-1.0.xsd">
09.
10. <bean id="idSpringWebFlowJasperReportsFlowController"
11. class="org.springframework.webflow.executor.mvc.FlowController">
12. <property name="flowExecutor"
ref="flowExecutorSpringWebFlowJasperReports" />
13. </bean>
14.
15. <flow:executor id="flowExecutorSpringWebFlowJasperReports"
16. registry-ref="flowRegistrySpringWebFlowJasperReports"
17. repository-type="singlekey"/>
18.
19. <flow:registry id="flowRegistrySpringWebFlowJasperReports">
20. <flow:location path="/WEB-INF/flows/springwebflowjasperreports-
flow.xml" />
21. </flow:registry>
22.
23.</beans>
For this example we must configure the view resolver, url mapping, and some Web MVC
beans. For that we must use springjasperreports-servlet.xml
view source
print?
01.<beans>
02.
03. <bean id="viewResolver"
04. class="org.springframework.web.servlet.view.ResourceBundleViewResol
ver">
05. <property name="basename" value="views"/>
06. </bean>
07.
08. <bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSo
urce">
09. <property name="cacheSeconds" value="5"/>
10. <property name="basename" value="/WEB-
INF/interproperties/messages"/>
11. </bean>
12.
13. <bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
14. <property name="mappings">
15. <props>
16. <prop key="/welcome.htm">idWelcomeController</prop>
17. <prop
key="/prereportsimplejasperreport.htm">idPreReportSimpleJasperReportControll
er</prop>
18. <prop
key="/reportsimplepdfjasperreport.htm">idReportSimplePdfJasperReportControll
er</prop>
19. <prop
key="/springwebflowjasperreports.htm">idSpringWebFlowJasperReportsFlowContro
ller</prop>
20. </props>
21. </property>
22. </bean>
23.
24. <bean id="idWelcomeController"
25. class="com.springjasperreports.controler.mvc.welcome.WelcomeCont
roller" />
26.
27. <bean id="idPreReportSimpleJasperReportController"
28. class="com.springjasperreports.controler.mvc.jasperreports.PreR
eportSimpleJasperReportController" />
29.
30.
31.</beans>
The bean declarations are clear by themselves. You should notice the two last beans
idWelcomeController and idPreReportSimpleJasperReportController. They are two simple
controllers that extend the super class AbstractController, both used for forward purposes.
Step 7: views.properties
All our views (jsp/pdf) must be configured in views.properties, for this, see below
view source
print?
01.welcome.(class) = org.springframework.web.servlet.view.JstlView
02.welcome.url = /WEB-INF/jsp/inicio.jsp
03.
04.prereportsimplejasperreport.(class) =
org.springframework.web.servlet.view.JstlView
05.prereportsimplejasperreport.url = /WEB-
INF/jsp/mvc/reportSimpleJasperReport.jsp
06.
07.springwebflowjasperreports-stepone.(class) =
org.springframework.web.servlet.view.JstlView
08.springwebflowjasperreports-stepone.url = /WEB-INF/jsp/flow/swfjr-
stepone.jsp
09.
10.springwebflowjasperreports-steptwo.(class) =
org.springframework.web.servlet.view.JstlView
11.springwebflowjasperreports-steptwo.url = /WEB-INF/jsp/flow/swfjr-
steptwo.jsp
12.
13.reportsimplepdfjasperreport.(class) =
org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
14.reportsimplepdfjasperreport.reportDataKey = datasource
15.reportsimplepdfjasperreport.url = /WEB-
INF/reports/SpringJasperReportsspring.jasper
The most important part is for the Pdf View used by:
ReportSimplePdfJasperReportController class
springwebflowjasperreports-printpdf view-state
view source
print?
01.<?xml version="1.0" encoding="ISO-8859-1" ?>
02.<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
03.<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
04.<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
05.
06.<html>
07. <head>
08. <title>Welcome</title>
09. </head>
10. <body>
11. <center>
12. <p>
13. This Simple tutorial show you how use <i>Spring Web MVC</i> and
<i>Spring Web Flow</i>
14. working together with <i>JasperReports</i>.
15. </p>
16. <ul>
17. <li>Spring Web MVC - JasperReports
18. <a
href="/springjasperreports/prereportsimplejasperreport.htm">start</a></li>
19.
20. <li>Spring Web Flow - JasperReports
21. <a href="/springjasperreports/springwebflowjasperreports.htm?
_flowId=springwebflowjasperreports-flow">
22. start</a>
23. </li>
24. </ul>
25. </center>
26. </body>
27.</html>
It only offers two links to start each type of example process, as illustrated here:
If we do click in the first link, it must show the reportSimpleJasperReport.jsp. Below is the
code
view source
print?
01.<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
02.<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
03.<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
04.<html>
05. <head>
06. <title>Spring Web MVC - JasperReports</title>
07. </head>
08. <body>
09. <center>
10.
11.
12.
13. <p>
14. Click in <i>Generate Pdf</i> button to open a Pdf Report
15. </p>
16. <form
action="/springjasperreports/reportsimplepdfjasperreport.htm" method="post"
>
17. <input type="submit" class="button" name="next"
value="Generate Pdf"/>
18. </form>
19. <p>
20. Click in <i>Go To Welcome Page</i> button if you want to
start again
21. </p>
22. <form action="/springjasperreports/welcome.htm"
method="post" >
23. <input type="submit" class="button" name="next" value="Go
To Welcome Page"/>
24. </form>
25. </center>
26. </body>
27.</html>
It only consist in two forms, with an url action for each one, the purposes are obvious. Below
the execution page
Note: I have configured my Web browser (Firefox/Opera) to open Adobe Reader to see the pdf
report
Now if we do click in the second link in inicio.jsp, it must start the flow process, then the first
view-state use swfjr-stepone.jsp, below the code
view source
print?
01.<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
02.<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
03.<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
04.<html>
05. <head>
06. <title>Spring Web Flow - JasperReports - Page One</title>
07. </head>
08. <body>
09. <center>
10. <p>
11. It is the first page of N pages of a flow process, it would be
a simple form.
12. For simplicity it flow consist only in two pages.
13. </p>
14. <form action="" method="post" >
15. <input type="hidden" name="_flowExecutionKey" value="$
{flowExecutionkey}"/>
16. <input type="submit" class="button" name="_eventId_next"
value="Go To Page Two"/>
17. </form>
18. </center>
19. </body>
20.</html>
If we do click in the button Go To Page Two we go to the next view-state and it use swfjr-
steptwo.jsp, below the code
view source
print?
01.<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
02.<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
03.<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
04.<html>
05. <head>
06. <title>Spring Web Flow - JasperReports - Page Two</title>
07. </head>
08. <body>
09. <p align="justify">
10. It is the last page of N pages of a flow process.
11. For simplicity according to the explanation it gives the
options to
12. <ul>
13. <li>Generate a pdf</li>
14. <li>Finish the flow process</li>
15. </ul>
16. In the case that you decide to finish the process without
generate the pdf
17. and then after some time you want to see the report
18. (obvious that the flow process is already terminated),
19. then you should use Spring Web MVC for get the report like a
simple search
20. </p>
21. <center>
22. <form action="" method="post" >
23. <input type="hidden" name="_flowExecutionKey" value="$
{flowExecutionkey}"/>
24. <input type="submit" class="button" name="_eventId_next"
value="Generate Pdf"/>
25.
26.
27.
28. <input type="submit" class="button" name="_eventId_end"
value="End Process"/>
29. </form>
30. </center>
31. </body>
32.</html>
Then the result desired is a pdf file, below the pdf generated
You would create your own war file and compile your SpringJasperReportsspring.jrxml with
Ant tasks. (In a few days I will attach the source code to share)
I hope that this tutorial help you, if you have some doubt or recommendation, please let me
know and sorry about my grammar.
In another Article, i will share perhaps the most important tutorial; the cumbersome case
about Spring/JasperReports integration but related with Sub-Reports.