Living life and Make it Better

life, learn, contribute

Endy Muhardin

Software Developer berdomisili di Jabodetabek, berkutat di lingkungan open source, terutama Java dan Linux.

Membuat subreport Jasper dalam SpringMVC

Pada artikel ini, kita akan membuat implementasi download file PDF/XLS dari aplikasi web. Fitur ini akan kita implementasi menggunakan library Jasper Report dan framework Spring MVC.

Projectnya akan kita buat menggunakan Maven, supaya bisa dibuka dengan baik (portable) di berbagai IDE. Untuk bisa memahami artikel ini dengan baik, pembaca harus sudah paham tentang Spring Framework dan Spring MVC. Yang belum paham Spring Framework bisa membaca artikel terdahulu tentang Dependency Injection. Sedangkan pembahasan tentang Spring MVC bisa dibaca di rangkaian artikel berseri tentang membuat aplikasi web dengan Spring MVC.

Source code lengkap dapat diakses di repository Github. Bagi yang ingin tahu urutan langkah-langkah implementasinya, bisa lihat commit history.

Setup Project

Pertama, kita setup dulu projectnya menggunakan Maven Archetype dengan perintah berikut

mvn archetype:create -DgroupId=com.muhardin.endy.belajar -DartifactId=belajar-springmvc-jasper

Kemudian konversi menjadi aplikasi web dengan cara:

  • edit pom.xml, ganti <packaging>jar</packaging> menjadi <packaging>war</packaging>
  • tambahkan file src/main/webapp/WEB-INF/web.xml
  • ini langkah opsional, tambahkan src/main/webapp/index.html supaya ada halaman Hello World

Kondisi project pada tahap ini bisa dilihat di commit 1fa6134d10

Setelah selesai di tahap ini, kita bisa buka projectnya menggunakan Netbeans atau Eclipse.

Aktivasi Spring MVC

Mulai dari yang mudah dulu, kita buat controller yang menampilkan Hello World dengan Spring MVC. Ini sekedar memastikan bahwa konfigurasi Spring MVC kita sudah benar, sehingga pada waktu implementasi Jasper Report nanti kita tidak perlu lagi memusingkan error Spring MVC.

Tambahkan dependensi Spring MVC di pom.xml

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

Saya menggunakan Maven properties untuk mendeklarasikan versi library. Ini akan memudahkan kalau di kemudian hari kita ingin mengupgrade versinya.

<properties>
    <org.springframework.version>4.0.2.RELEASE</org.springframework.version>
</properties>

Agar bisa memproses file JSP, kita tambahkan juga library jstl.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>${jstl.version}</version>
    <scope>runtime</scope>
</dependency>

Selanjutnya, deklarasikan DispatcherServlet milik Spring di web.xml

<servlet>
    <servlet-name>belajar</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>belajar</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Kita harus membuat file konfigurasi sesuai dengan nama servlet. Karena namanya belajar, maka file yang harus dibuat adalah belajar-servlet.xml. Isinya tidak banyak, seperti ini:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven/>
    <mvc:default-servlet-handler />

    <context:component-scan base-package="com.muhardin.endy.belajar.springmvcjasper.controller" />
    
    <bean id="jstlViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/templates/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
</beans>

Sediakan file halo.jsp dalam folder WEB-INF/templates/jsp. Isinya tidak saya pasang di sini, silahkan lihat sendiri di Github.

Buat controller dalam package com.muhardin.endy.belajar.springmvcjasper.controller, sesuai konfigurasi dalam belajar-servlet.xml. Isi file bisa dilihat di Github.

Pada tahap ini, kita bisa menjalankan aplikasinya dengan perintah mvn clean package tomcat:run dan browse ke http://localhost:8080/belajar-springmvc-jasper/halo

Kondisi folder project pada tahap ini bisa dilihat di sini.

Aktivasi Jasper Report

Kita harus membuat dulu template reportnya. Gunakan iReport untuk mendesain template secara visual, supaya lebih mudah. Berikut screenshot report yang saya buat

Foto

Semua template Jasper Report kita simpan dalam folder src/main/webapp/WEB-INF/templates/jrxml.

Agar bisa memproses template report tersebut, kita tambahkan dulu library Jasper Report di pom.xml

<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>${jasperreports.version}</version>
    <scope>runtime</scope>
</dependency>

Cukup gunakan scope runtime karena kita tidak perlu import class Jasper di kode program kita. Tambahkan juga dependensi javax.servlet.http supaya kita bisa menggunakan class HttpServletRequest nantinya. Scopenya kita gunakan provided, karena sudah disediakan dalam application server (misal: Tomcat).

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>

Selanjutnya, kita tinggal isi data yang akan ditampilkan dalam dokumen PDF/XLS. Ini kita lakukan di kode program Java dalam class HaloController. Berikut methodnya

@RequestMapping(value = "/anggota/export*", method = RequestMethod.GET)
public ModelMap exportDataAnggota(HttpServletRequest request) {
    String uri = request.getRequestURI();
    String format = uri.substring(uri.lastIndexOf(".") + 1);

    return new ModelMap()
            .addAttribute("format", format)
            .addAttribute("tanggal", new Date())
            .addAttribute("dataSource", service.semuaAnggota());
}

Pada kode program di atas, pertama kita ambil dulu akhiran di URL yang diakses user. Contohnya, bila user mengakses http://localhost:8080/belajar-springmvc-jasper/anggota/export.pdf, maka variabel format akan berisi pdf. Variabel format ini akan digunakan Spring untuk menentukan jenis outputnya, apakah PDF, XLS, CSV, dsb.

Kita isi variabel apapun yang kita butuhkan dalam report. Pada contoh di atas, kita kirim dua variabel yaitu tanggal dan dataSource. Variabel tanggal akan menjadi parameter dalam Jasper Report, sedangkan dataSource akan menjadi sumber data yang akan ditampilkan dalam band detail. Untuk lebih jelasnya, silahkan buka file templatenya dengan menggunakan iReport.

Selanjutnya, kita konfigurasi Spring agar request ke url http://localhost:8080/belajar-springmvc-jasper/anggota/export.pdf diteruskan ke Jasper Report. Kita buat deklarasi resolver untuk Jasper Report dalam belajar-servlet.xml sebagai berikut

<bean id="jasperViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
    <property name="location" value="classpath:jasper-views.xml"/>
    <property name="order" value="0"/>
</bean>

Tambahkan juga property order di konfigurasi JSP supaya dia dijalankan setelah Jasper Report.

<bean id="jstlViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/templates/jsp/"/>
    <property name="suffix" value=".jsp"/>
    <property name="order" value="1"/>
</bean>

Ini kita lakukan karena resolver JSP tidak bisa mengecek apakah templatenya ditemukan atau tidak. Dia akan langsung mengeluarkan pesan error. Dengan resolver Jasper dieksekusi duluan, maka flownya akan seperti ini:

  1. Dari controller terima nama view /anggota/export.pdf
  2. Cari view dengan nama tersebut dalam jasperViewResolver
  3. Kalau tidak ketemu lanjutkan cari dalam jstlViewResolver
  4. Kalau tidak ketemu juga, keluarkan pesan error

Kondisi folder project pada tahap ini bisa dilihat di sini

Pada tahap ini kita sudah bisa menghasilkan file PDF ataupun XLS menggunakan Jasper Report dan Spring MVC. Tentunya pada aplikasi sebenarnya data diambil dari database. Tapi untuk menyederhanakan masalah agar kita bisa fokus ke konfigurasi Jasper dan Spring, maka data yang ditampilkan kita hardcode saja.

Selanjutnya, kita akan mencoba konfigurasi yang lebih sulit, yaitu sub report.

Sub Report

Subreport adalah report di dalam report. Ini adalah fitur canggih dari Jasper Report. Kita tidak akan membahas detail tentang apa itu subreport. Silahkan baca artikel ini dan ini untuk memahami apa itu subreport.

Satu report induk bisa menampung banyak subreport. Masing-masing subreport memiliki template dan dataSource sendiri. Untuk itu, kita perlu memberitahukan pada semua pihak tentang lokasi / nama file template subreport dan nama variabel dataSource yang digunakan di subreport.

Kita mulai dari desain template induk terlebih dulu. Ini kita lakukan di iReport. Drag and drop icon subreport di Palette ke template. iReport akan menampilkan wizard untuk membantu kita.

Foto

Saya lebih suka membuat templatenya secara terpisah, kemudian menyatukannya secara manual. Oleh karena itu, kita pilih Just create subreport element.

Hasilnya sebagai berikut.

Foto

Sebetulnya di dokumentasi Spring MVC ada penjelasan tentang cara menggunakan subreport.

Foto

Tapi sayangnya, isinya tidak nyambung sama penjelasan di atasnya. Penjelasan report sederhana dibuat menggunakan konfigurasi file properties, sedangkan penjelasan subreport dibuat menggunakan konfigurasi file XML. Perbedaannya bisa dilihat di sini atau pada gambar di bawah.

Foto

Selanjutnya, kita tambahkan parameter di desain report induk kita. Bisa menggunakan GUI ataupun langsung edit XMLnya. Kali ini saya pakai XML saja supaya bisa copy-paste

Foto

Kita tambahkan dua parameter, yaitu SubReportKantor dan dataSourceSubreport. Kedua parameter ini kita gunakan pada deklarasi subreport yang sudah ditambahkan iReport pada waktu kita drag and drop tadi.

Foto

Perhatikan label X dan Y. Itu akan kita gunakan pada konfigurasi lainnya.

Nama variabel dataSourceSubreport yang ditandai dengan label X kita gunakan untuk menyuplai data yang dibutuhkan subreport dari dalam kode program Java.

Foto

Selanjutnya kita edit konfigurasi Jasper Report di file jasper-views.xml. Tambahkan lokasi template subreport dan nama variabel yang digunakan untuk dataSourcenya.

Foto

Selesai sudah. Silahkan coba akses lagi http://localhost:8080/belajar-springmvc-jasper/anggota/export.pdf untuk melihat hasil akhirnya.

Foto

FAQ

Pada umumnya, kita semua menggunakan konfigurasi Jasper yang berbasis file properties, karena itulah yang dicontohkan di dokumentasi Spring Framework. Pada waktu muncul kebutuhan subreport, ternyata file konfigurasinya XML.

Apakah saya harus konversi semua konfigurasi properties menjadi XML ??

Jangan khawatir. Kita bisa menggunakan dua-duanya sekaligus. Tidak perlu pilih salah satu. Konfigurasi report yang lama tidak perlu dibuang/ditulis ulang menjadi xml. Cukup deklarasikan dua view resolver, yang satu properties, satu lagi XML. Begini contohnya

<bean id="propertiesJasperViewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
	<property name="basename" value="views"/>
	<property name="order" value="0"/>
</bean>

<bean id="xmlJasperViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
    <property name="location" value="classpath:jasper-views.xml"/>
    <property name="order" value="1"/>
</bean>

<bean id="jstlViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/templates/jsp/"/>
    <property name="suffix" value=".jsp"/>
    <property name="order" value="2"/>
</bean>

Dengan cara di atas, berikut flow Spring MVC dalam mencari template yang sesuai:

  1. Dari controller terima nama view /anggota/export.pdf
  2. Cari view dengan nama tersebut dalam propertiesJasperViewResolver
  3. Kalau tidak ketemu lanjutkan cari dalam xmlJasperViewResolver
  4. Kalau masih tidak ketemu juga lanjutkan cari dalam jstlViewResolver
  5. Kalau tidak ketemu juga, keluarkan pesan error

Demikian penjelasan tentang integrasi Spring MVC dan Jasper Report. Source code lengkap bisa diambil di Github

Semoga bermanfaat