Spring MVC - JasperReports View

[Updated: Oct 1, 2017, Created: Sep 28, 2017]

This example demonstrates how to use JasperReports Library in a Spring MVC application. JasperReports is a reporting engine. It takes input data coming from a data source (an implementation of Jasper's JRDataSource interface), fills the data source values into a user defined report template (an xml file with .jrxml extension) and then uses an exporter (an implementation of Jasper's JRExporter interface) to render resultant document in one of the variety of formats including HTML, PDF, Excel, OpenOffice and Word.

Example

In this example, we will use the following Jasper components:

  • JRBeanCollectionDataSource It is an implementation of JRDataSource which is an Jasper abstraction of data source. This data source wraps a collection of JavaBean objects.

  • HtmlExporter It is an implementation of JRExporter interface which renders the report document in HTML format.

  • Jrxml file We will also need to write a jrxml file to define the report template.

Additional Maven Dependency

pom.xml

<dependency>
   <groupId>net.sf.jasperreports</groupId>
   <artifactId>jasperreports</artifactId>
   <version>6.4.1</version>
   <exclusions>
     <exclusion>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-core</artifactId>
     </exclusion>
   </exclusions>
</dependency>

Above JasperReports dependency uses jackson-core 2.1.4. We need to exclude that because first of all we are not using any Jackson related feature in this example and secondly Spring expects Jackson's minimum version to be 2.5.0 for MappingJackson2HttpMessageConverter to work which is automatically initialized if the Jackson's ObjectMapper is on the classpath.

Java Config class

In this example, we are going to use BeanNameViewResolver for resolving the Jasper view. We will register an implementation of View as a bean and will return the bean name as a view name from the Spring controller. Check out this simple example of BeanNameViewResolver as well.

@EnableWebMvc
@Configuration
@ComponentScan
public class MyWebConfig {
  @Bean
  public ViewResolver beanNameViewResolver() {
      BeanNameViewResolver resolver = new BeanNameViewResolver();
      return resolver;
  }

  @Bean
  public ViewResolver jspViewResolver() {
      InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
      viewResolver.setPrefix("/WEB-INF/views/");
      viewResolver.setSuffix(".jsp");
      return viewResolver;
  }
}

Implementing the View

Spring classes for JasperReport support are based on old deprecated Jasper API. We have to extend AbstractView to use the new JasperReport API directly.

package com.logicbig.example;

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleHtmlExporterOutput;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.AbstractView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

@Component("forexView")
public class CurrencyRateHtmlView extends AbstractView {
  private JasperReport currencyRatesReport;

  @Override
  protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
                                         HttpServletResponse response) throws Exception {
      response.setContentType("text/html");
      List<CurrencyRate> rates = (List<CurrencyRate>) model.get("todayCurrencyRates");
      //data source
      JRDataSource dataSource = getDataSource(rates);
      //compile jrxml template and get report
      JasperReport report = getReport();
      //fill the report with data source objects
      JasperPrint jasperPrint = JasperFillManager.fillReport(report, null, dataSource);
      //export to html
      HtmlExporter exporter = new HtmlExporter(DefaultJasperReportsContext.getInstance());
      exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
      exporter.setExporterOutput(new SimpleHtmlExporterOutput(response.getWriter()));
      exporter.exportReport();
  }

  private JRDataSource getDataSource(List<CurrencyRate> rates) {
      JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(rates);
      return dataSource;
  }

  public JasperReport getReport() throws JRException {
      if (currencyRatesReport == null) {//compile only once lazily
          InputStream stream = getClass().getResourceAsStream("/rates.jrxml");
          currencyRatesReport = JasperCompileManager.compileReport(stream);
      }
      return currencyRatesReport;
  }
}
public class CurrencyRate {
  private String currencyPair;
  private Date date;
  private BigDecimal askPrice;
  private BigDecimal bidPrice;
    .............
}

src/main/resources/rates.jrxml

<?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="rates-template" pageWidth="595" pageHeight="842"
              columnWidth="555" leftMargin="20" rightMargin="20"
              topMargin="20" bottomMargin="20"
              uuid="3737c8f8-35e7-4ea0-bf9f-c557f6bbbdf3">

        <field name="currencyPair" class="java.lang.String"/>
        <field name="date" class="java.util.Date"/>
        <field name="askPrice" class="java.math.BigDecimal"/>
        <field name="bidPrice" class="java.math.BigDecimal"/>

    <columnHeader>
        <band height = "50">
            <staticText>
                <reportElement x = "0" y = "0" width = "120" height = "50" />
                <textElement verticalAlignment = "Middle">
                    <font size="16" isBold = "true" />
                </textElement>
                <text><![CDATA[Currency Pair]]></text>
            </staticText>
            <staticText>
                <reportElement x = "120" y = "0" width = "120" height = "50" />
                <textElement verticalAlignment = "Middle">
                    <font size="16" isBold = "true" />
                </textElement>
                <text><![CDATA[Date]]></text>
            </staticText>
            <staticText>
                <reportElement x = "240" y = "0" width = "120" height = "50" />
                <textElement verticalAlignment = "Middle">
                    <font size="16" isBold = "true" />
                </textElement>
                <text><![CDATA[Ask Price]]></text>
            </staticText>
            <staticText>
                <reportElement x = "360" y = "0" width = "120" height = "50" />
                <textElement verticalAlignment = "Middle">
                    <font size="16" isBold = "true" />
                </textElement>
                <text><![CDATA[Bid Price]]></text>
            </staticText>
       </band>
    </columnHeader>

    <detail>
        <band height="25">
            <textField>
                <reportElement x="0" y="0" width="120" height="25"/>
                <textElement>
                    <font size="14" />
                </textElement>
                <textFieldExpression class="java.lang.String">
                    <![CDATA[$F{currencyPair}]]></textFieldExpression>
            </textField>
            <textField pattern="dd.MM.yyyy">
                <reportElement x="120" y="0" width="120" height="25"/>
                <textElement>
                    <font size="14" />
                </textElement>
                <textFieldExpression class="java.util.Date">
                    <![CDATA[$F{date}]]></textFieldExpression>
            </textField>
            <textField pattern="#,##0.00">
                <reportElement x="240" y="0" width="120" height="25"/>
                <textElement>
                    <font size="14" />
                </textElement>
                <textFieldExpression class="java.math.BigDecimal">
                    <![CDATA[$F{askPrice}]]></textFieldExpression>
            </textField>
        <textField pattern="#,##0.00">
            <reportElement x="360" y="0" width="120" height="25"/>
            <textElement>
                <font size="14" />
            </textElement>
            <textFieldExpression class="java.math.BigDecimal">
                <![CDATA[$F{bidPrice}]]></textFieldExpression>
        </textField>
        </band>
    </detail>
</jasperReport>

Writing a Spring Controller

@Controller
@RequestMapping("/")
public class CurrencyRateController {

  @GetMapping("/")
  public String mainView() {
      return "main";
  }

  @GetMapping("/exchangeRates")
  public String handleForexRequest(Model model) {
      model.addAttribute("todayCurrencyRates", getTodayForexRates());
      return "forexView";
  }

  private List<CurrencyRate> getTodayForexRates() {
      //dummy rates
      List<CurrencyRate> currencyRates = new ArrayList<>();
      Date today = new Date();
      List<Currency> currencies = new ArrayList<>(Currency.getAvailableCurrencies());

      for (int i = 0; i < currencies.size(); i += 2) {
          String currencyPair = currencies.get(i) + "/" + currencies.get(i + 1);
          CurrencyRate cr = new CurrencyRate();
          cr.setCurrencyPair(currencyPair);
          cr.setDate(today);
          BigDecimal bidPrice = new BigDecimal(Math.random() * 5 + 1);
          bidPrice = bidPrice.setScale(3, RoundingMode.CEILING);
          cr.setBidPrice(bidPrice);
          BigDecimal askPrice = new BigDecimal(bidPrice.doubleValue() + Math.random() * 2 + 0.5);
          askPrice = askPrice.setScale(3, RoundingMode.CEILING);
          cr.setAskPrice(askPrice);

          currencyRates.add(cr);
      }
      return currencyRates;
  }
}

src/main/webapp/WEB-INF/views/main.jsp

<html>
<body>
<h2>Spring Jasper Report View Example</h2>
<a href="/exchangeRates">Get the today's Currency Rates</a>
</body>
</html>

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

Output

clicking on the link:

Example Project

Dependencies and Technologies Used :

  • spring-webmvc 4.3.11.RELEASE: Spring Web MVC.
  • javax.servlet-api 3.1.0 Java Servlet API
  • jasperreports 6.4.1: JasperReports Library.
  • JDK 1.8
  • Maven 3.3.9

Spring JasperReports View Example Select All Download
  • spring-jasper-view-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
        • webapp
          • WEB-INF
            • views

See Also