My Works

SpringMVC WebApplicationInitializer Integration with Jasper Reports

Previously the springmvcwebinitializer example illustrated a simple example of SpringMvC with WebApplicationInitializer where in web.xml was not required for initialising the servlet. The context and beans were programmatically loaded based on annotation. Now we are going to extend the SpringMVC Application based on WebapplicationIntitializer to integrate Jasper Reports.

  1. Project Dependencies.
  2. Create a Related bean.
  3. Create a JRXML file.
  4. Create WebInitializer and Create MVC Context Configuration programmatically.
  5. Create View Configuration programmatically.
  6. Create JSP page for the Current example.
  7. Add a unit test for your controller.
  8. Based on the Unit test create the controller and Add methods in the controller to produce the report views.
  9. Deploy and Run.

1.Project Dependencies.

JDK 1.6 or above, In this case have chosen Tomcat 7.0.37 , Spring MVC jars, junit jar and logging jars are the ones that would be needed. The pom file dependencies are listed below.

	
		
<properties>
<spring.version>3.2.3.RELEASE</spring.version>
</properties>

<dependencies>

<!-- servlet library -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>

<!-- log library slf4j-bridge for commons-logging or you can use log4j directly.. -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.0</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.0</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.0</version>
</dependency>

<!-- spring dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>


<!-- apache commons library -->
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>2.1</version>
</dependency>


<!-- jasperreports dependencies -->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>4.0.1</version>
<type>jar</type>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</exclusion>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
<exclusion>
<artifactId>commons-digester</artifactId>
<groupId>commons-digester</groupId>
</exclusion>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>

<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.6</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7.0</version>
</dependency>

</dependencies>

	
	
	

Packing using the maven plugins...

	
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<directory>src\main\webapp</directory>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
<finalName>WebInitializerIntegrateJasperReports</finalName>
</build>



	

2.Create a Related bean.

Create a Bean that would eventually serve as Data Source for the Report. Essentially the bean field values are mapped in to report field values.

	
public class ReportBean {

private String firstName;
private String lastName;
private String emailAddress;
private Date createdDate;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmailAddress() {
return emailAddress;
}

public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}

public Date getCreatedDate() {
return createdDate;
}

public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}

}


3.Create a JRXML file.

In Jasper Reports the primary report description is represented as JRXML file. In this example a very simple and basic Report is created. To start with use iReportDesigner with EmptyDatasource and define fields same as your ReportBean class variables. Latest or Older versions of iReportDesigner can be used to obtain the required SimpleReport JRXML file for the current Example . The latest versions of iReportDesinger adds uuid attribute.This could be avoided either by using the older version of iReportDesigner or by saving the .jrxml file after removing the uuid attribute. Now save the jrxml file in the jasper folder in the src/main/resources.More info in this regard, Please refer designing jasper report and creating basic report.



<?xml version="1.0" encoding="UTF-8"?>
<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="SimpleJasperReport" language="groovy" pageWidth="842" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
<property name="ireport.zoom" value="1.0"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="12"/>
<queryString>
<![CDATA[]]>
</queryString>
<field name="firstName" class="java.lang.String"/>
<field name="lastName" class="java.lang.String"/>
<field name="emailAddress" class="java.lang.String"/>
<field name="createdDate" class="java.util.Date"/>
<background>
<band splitType="Stretch"/>
</background>
<title>
<band height="79" splitType="Stretch">
<staticText>
<reportElement  x="330" y="30" width="70" height="20"/>
<textElement/>
<text><![CDATA[ExampleReport]]></text>
</staticText>
</band>
</title>
<pageHeader>
<band height="35" splitType="Stretch">
<staticText>
<reportElement  x="330" y="0" width="121" height="20"/>
<textElement/>
<text><![CDATA[AccountReport]]></text>
</staticText>
</band>
</pageHeader>
<columnHeader>
<band height="70" splitType="Stretch">
<staticText>
<reportElement  x="104" y="50" width="70" height="20"/>
<textElement/>
<text><![CDATA[firstName]]></text>
</staticText>
<staticText>
<reportElement  x="243" y="50" width="70" height="20"/>
<textElement/>
<text><![CDATA[lastName]]></text>
</staticText>
<staticText>
<reportElement  x="400" y="50" width="101" height="20"/>
<textElement/>
<text><![CDATA[emailAddress]]></text>
</staticText>
<staticText>
<reportElement  x="593" y="50" width="99" height="20"/>
<textElement/>
<text><![CDATA[createdDate]]></text>
</staticText>
</band>
</columnHeader>
<detail>
<band height="125" splitType="Stretch">
<textField>
<reportElement  x="104" y="10" width="94" height="30"/>
<textElement/>
<textFieldExpression><![CDATA[$F{firstName}]]></textFieldExpression>
</textField>
<textField>
<reportElement  x="243" y="10" width="70" height="30"/>
<textElement/>
<textFieldExpression><![CDATA[$F{lastName}]]></textFieldExpression>
</textField>
<textField>
<reportElement  x="400" y="10" width="101" height="30"/>
<textElement/>
<textFieldExpression><![CDATA[$F{emailAddress}]]></textFieldExpression>
</textField>
<textField>
<reportElement  x="593" y="10" width="99" height="30"/>
<textElement/>
<textFieldExpression><![CDATA[$F{createdDate}]]></textFieldExpression>
</textField>
</band>
</detail>
<columnFooter>
<band height="45" splitType="Stretch"/>
</columnFooter>
<pageFooter>
<band height="54" splitType="Stretch"/>
</pageFooter>
<summary>
<band height="42" splitType="Stretch"/>
</summary>
</jasperReport>




4.Create WebInitializer and Create MVC Context Configuration programmatically.

Please follow the description given in the springmvcwebinitializer example for creating the WebInitializer and MVC Context Configuration programmatically.More Info in this regard, Please refer documentation on WebApplicationInitializer and WebMvcConfigurerAdapter.


public class SrinivasExampleIntegratingJasperReports implements WebApplicationInitializer {

private static final Logger logger = LoggerFactory.getLogger(SrinivasExampleIntegratingJasperReports.class);

/* (non-Javadoc)
* @see org.springframework.web.WebApplicationInitializer#onStartup(javax.servlet.ServletContext)
*/
@Override
public void onStartup(ServletContext container) {
logger.info("Started to pickup the annotated classes");
startServlet(container);
}


private void startServlet(final ServletContext container) {
WebApplicationContext dispatcherContext = registerContext(MvcContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
ServletRegistration.Dynamic dispatcher;
dispatcher = container.addServlet("dispatcher",dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.html");
}

/**
* Register context.
*
* @param annotatedClasses the Class type variable argument of classes that needs to be registered to the context.
* @return the web application context
*/
private WebApplicationContext registerContext(final Class<?>... annotatedClasses) {
logger.info("Using AnnotationConfigWebApplicationContext createContext");
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}

}

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "org.srinivas.siteworks","org.srinivas.siteworks.controllers" })
public class MvcContextConfiguration extends WebMvcConfigurerAdapter {

/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(MvcContextConfiguration.class);

/* (non-Javadoc)
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureDefaultServletHandling(org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer)
*/
@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
logger.info("WebMvcContextConfiguration: configureDefaultServletHandling Method");
configurer.enable();
}

}



5.Create View Configuration programmatically.

This class beans are loaded during the component scan of class MvcContextConfiguration.Thereby it is registered to the servlet. In this Example a bean for view resolver of type BeanNameViewResolver is loaded. This enables loading view based on respective bean name that returns the View. The view beans related to Jasper Reports formats are pdfReport, xlsReport, htmlReport, csvReport. view bean jasperreport is of type InternalResourceView providing view for jasperreport jsp page.More info in this regard, Please refer documentation on jasperreports.



@Configuration
public class ViewConfiguration {

public static final String REPORTCONTROLLER_JASPER_REPORT_DATASOURCE = "datasource";
private static final String VIEWCONFIGURATION_JASPER_SIMPLE_JASPER_REPORT_JRXML_LOCATION = "classpath:jasper/SimpleJasperReport.jrxml";
private static final Logger logger = LoggerFactory.getLogger(ViewConfiguration.class);

@Bean
public ViewResolver beanViewResolver(){
BeanNameViewResolver viewResolver = new BeanNameViewResolver();
viewResolver.setOrder(1);
return viewResolver;
}

@Bean
public View jasperreport(){
InternalResourceView view = new InternalResourceView();
view.setUrl("/WEB-INF/displays/jasperreport.jsp");
return view;
}

@Bean
public View pdfReport() {
logger.info("ViewConfiguration pdfReport()");
JasperReportsPdfView userReportPdfView = new JasperReportsPdfView();
userReportPdfView.setUrl(VIEWCONFIGURATION_JASPER_SIMPLE_JASPER_REPORT_JRXML_LOCATION);
logger.info("JRXML" + VIEWCONFIGURATION_JASPER_SIMPLE_JASPER_REPORT_JRXML_LOCATION);
userReportPdfView.setReportDataKey(REPORTCONTROLLER_JASPER_REPORT_DATASOURCE);
return userReportPdfView;
}

@Bean
public View xlsReport() {
logger.info("ViewConfiguration xlsReport()");
JasperReportsXlsView userReportXlsView = new JasperReportsXlsView();
userReportXlsView.setUrl(VIEWCONFIGURATION_JASPER_SIMPLE_JASPER_REPORT_JRXML_LOCATION);
userReportXlsView.setReportDataKey(REPORTCONTROLLER_JASPER_REPORT_DATASOURCE);
return userReportXlsView;
}

@Bean
public View htmlReport() {
logger.info("ViewConfiguration htmlReport()");
JasperReportsHtmlView userReportHtmlView = new JasperReportsHtmlView();
userReportHtmlView.setUrl(VIEWCONFIGURATION_JASPER_SIMPLE_JASPER_REPORT_JRXML_LOCATION);
userReportHtmlView.setReportDataKey(REPORTCONTROLLER_JASPER_REPORT_DATASOURCE);
return userReportHtmlView;
}

@Bean
public View csvReport() {
logger.info("ViewConfiguration csvReport()");
JasperReportsCsvView userReportCsvView = new JasperReportsCsvView();
userReportCsvView.setUrl(VIEWCONFIGURATION_JASPER_SIMPLE_JASPER_REPORT_JRXML_LOCATION);
userReportCsvView.setReportDataKey(REPORTCONTROLLER_JASPER_REPORT_DATASOURCE);
return userReportCsvView;
}

}



6.Create JSP page for the Current example.

We are creating a simple jsp page which takes the model attribute message that was set in the Controller and provides download links for jasper engine based pdf reports and jasper engine based xls reports.



<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>My Works:WebApplicationInitializerIntegrateJasperReports</title>
</head>
<body>
<table border=0 width="50%" style="margin: auto;">
<tr>
<td colspan=2 align="center" style="text-decoration:underline; font-weight:bold;">${message}</td>
</tr>
<tr>
<td colspan=2 >Download report in below formats:</td>
</tr>
<tr>
<td style="border-style: groove; "><a href="jasperreport/xls.html">Download Excel</a></td>
<td style="border:groove;" ><a href="jasperreport/pdf.html">Download PDF</a></td>
</tr>
</table>
</body>
</html>


7.Add a unit test for your controller.

We are executing the unit test using SpringJUnit4ClassRunner. We are actually checking the JasperReportsController for successful status,correct return of view string and correct return of message attribute. We are also checking for successful status for both pdf and xls reports. More info in this regard, Please refer documentation on MockMvC.


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class JasperReportsControllerTest {

private static final Logger logger = LoggerFactory.getLogger(JasperReportsControllerTest.class);

@Autowired
private JasperReportsController jasperReportsController;

@Test
public void testJasperReportsPage() {
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(this.jasperReportsController).build();
try {
mockMvc.perform(MockMvcRequestBuilders.get("/jasperreport.html"))
.andExpect(status().isOk())
.andExpect(view().name("jasperreport"))
.andExpect(forwardedUrl("jasperreport"))
.andExpect(handler().methodName("reportPage"))
.andExpect(
model().attribute(
"message",
JasperReportsController.STRING_MESSAGE_WELCOME_TO_WEB_APPLICATION_INITIALISER_INTEGRATED_WITH_JASPER_REPORTS))	;

} catch (Exception e) {
logger.info(e.getMessage());
fail("Failed Due to: "+e.getMessage());
}

}

@Test
public void testJasperReportsPdfPage() {
null
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(this.jasperReportsController).build();
try {
mockMvc.perform(MockMvcRequestBuilders.get("/jasperreport/pdf.html"))
.andExpect(status().isOk())
.andExpect(view().name("pdfReport"))
.andExpect(forwardedUrl("pdfReport"))
.andExpect(handler().methodName("generatePdfReport"));

} catch (Exception e) {
logger.info(e.getMessage());
fail("Failed Due to: "+e.getMessage());
}

}

@Test
public void testJasperReportsXLSPage() {
null
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(this.jasperReportsController).build();
try {
mockMvc.perform(MockMvcRequestBuilders.get("/jasperreport/xls.html"))
.andExpect(status().isOk())
.andExpect(view().name("xlsReport"))
.andExpect(forwardedUrl("xlsReport"))
.andExpect(handler().methodName("generateXlsReport"));
} catch (Exception e) {
logger.info(e.getMessage());
fail("Failed Due to: "+e.getMessage());
}

}

@Configuration
static class JasperReportsControllerTestConfiguration {

@Bean
public JasperReportsController jasperReportsController() {
return new JasperReportsController();
}
}

}


8.Based on the Unit test create the controller and Add methods in the controller to produce the report views.

Based on the expected result in the Unit test created above, Now create the controller JasperreportController. This Controller has a method reportPage which displays the jasperreport.jsp with the populated message attribute and the download links for jasper engine based pdf Report and jasper engine based xls Report. The method generatePdfReport and generateXlsReport use the JRDataSource to add collection of ReportBean. This Collection of ReportBean is put in to a Map object as corresponding value for the key datasource. This datasource further renders the respective view with view name pdfReport and xlsReport in the current example. Although JasperReports supports other formats as mentioned in the ViewConfiguration.class, Only two methods for rendering two formats have been provided for in the JasperreportController of current example . Remaining Formats can be applied like the currently provided methods generatePdfReport and generateXlsReport in the controller.



@Controller
@RequestMapping(value = "/jasperreport")
public class JasperReportsController {

public static final String REPORTCONTROLLER_REPORT_TYPE_BEAN_NAME_XLS_REPORT = "xlsReport";
public static final String REPORTCONTROLLER_REPORT_TYPE_BEAN_NAME_PDF_REPORT = "pdfReport";
public static final String STRING_MESSAGE_WELCOME_TO_WEB_APPLICATION_INITIALISER_INTEGRATED_WITH_JASPER_REPORTS = "Welcome to WebApplication Initialiser Integrated with JasperReports Page";
private static final Logger logger = LoggerFactory.getLogger(JasperReportsController.class);

@RequestMapping(method = RequestMethod.GET)
public String reportPage(Model model) {
logger.info("JasperReportsController");
model.addAttribute("message",STRING_MESSAGE_WELCOME_TO_WEB_APPLICATION_INITIALISER_INTEGRATED_WITH_JASPER_REPORTS);
return "jasperreport";
}

@RequestMapping(value = "/pdf", method = RequestMethod.GET)
public ModelAndView generatePdfReport(ModelAndView modelAndView) {
logger.info("ReportController generatePdfReport Method");
Map<String, Object> parameterMap = new HashMap<String, Object>();
List<ReportBean> dataList = new ArrayList<ReportBean>();
dataList.add(createReportData());
JRDataSource JRdataSource = new JRBeanCollectionDataSource(dataList);
parameterMap.put(REPORTCONTROLLER_JASPER_REPORT_DATASOURCE, JRdataSource);
logger.info("rendering the pdf view");
modelAndView = new ModelAndView(REPORTCONTROLLER_REPORT_TYPE_BEAN_NAME_PDF_REPORT, parameterMap);
return modelAndView;
}

@RequestMapping(value = "/xls", method = RequestMethod.GET)
public ModelAndView generateXlsReport(ModelAndView modelAndView) {
logger.info("ReportController generateXlsReport Method");
Map<String, Object> parameterMap = new HashMap<String, Object>();
List<ReportBean> dataList = new ArrayList<ReportBean>();
dataList.add(createReportData());
JRDataSource JRdataSource = new JRBeanCollectionDataSource(dataList);
parameterMap.put(REPORTCONTROLLER_JASPER_REPORT_DATASOURCE, JRdataSource);
logger.info("rendering the xls view");
modelAndView = new ModelAndView(REPORTCONTROLLER_REPORT_TYPE_BEAN_NAME_XLS_REPORT, parameterMap);
return modelAndView;
}

public ReportBean createReportData(){
ReportBean reportBean = new ReportBean();
reportBean.setFirstName("Srinivas");
reportBean.setLastName("Jasti");
reportBean.setEmailAddress("srinivas.jasti@techbrightworks.com");
reportBean.setCreatedDate(new Date());
return reportBean;
}

}



9.Deploy and Run.

Now Build the Project, the Corresponding Maven commands are available in the ReadMex.txt in the Downloadable example provided below. I have deployed and checked for some of versions from Tomcat7.0.30 and above. Start the web server and assuming localhost with port 8080. http://localhost:8080/WebInitializerIntegrateJasperReports/jasperreport.html displays with populated message attribute and two downloadable links for each format of Jasper Report provided in the current example. If the browser supports adobe Reader plugin then http://localhost:8080/WebInitializerIntegrateJasperReports/jasperreport/pdf.html displays report in pdf format otherwise without the adobe Reader plugin pdf file is simply downloaded. http://localhost:8080/WebInitializerIntegrateJasperReports/jasperreport/xls.html downloads the xls report however on Interner Explorer browser it can be opened with Microsoft Excel. To check and work on the current example you can download the Current Worked Example from here..

Jasper Report Page with Download Links for Formats

Jasper Report Page

Jasper Report in PDF format with Adobe Plugin enabled in the Browser

Jasper Report in PDF format with Adobe Plugin enabled

Jasper Report in XLS format on IE Browser

Jasper Report in XLS format on IE Browser