CLOVER🍀

That was when it all began.

JasperReportsを触る

仕事で、PDF生成のためにJasperReportsを初めて使っているのですが、仕事中にこれがあんまりよくわからなくなってハマりだしたので、休みを利用してちょっと勉強してみることにしました。

なんか、調べてみてもあんまりブログとかの情報がヒットしないのですが、けっこうマイナーな話題なのでしょうか?JasperReports、PDF生成って…。

JasperReportsは、PDFに限らずテンプレートXMLからHTMLやExcelを生成できるソフトウェアらしいのですが、自分の周りではPDF生成に使われていることしか聞いたことがありません。そして、テンプレートXMLの生成にはGUIツールである、iReportを使用します。

JasperReports
http://jasperforge.org/projects/jasperreports
iReport
http://jasperforge.org/projects/ireport

まずは、iReportで簡単な帳票を作成してみます。上述のiReportのページから、iReport本体をダウンロードして解凍します。自分が使用した時は、「iReport-4.1.1.tar.gz」をダウンロードしました。

解凍したら、binディレクトリに移動してiReportを起動します。

$ cd iReport-4.1.1/bin/
$ ./ireport &

ちなみに、iReportってNetBeansベースでできているみたいですね。外観も、どことなくNetBeansを連想します。起動画面はこちら。

では、起動したiReportを使用して帳票を作っていきます。メニューの「File」→「New」から新規ファイル作成ウィザードを起動します。最初にテンプレートの選択を求められるので、適当なものを選んで「Open this Template」を選択します。

あとは、「Next」を押しながらXMLファイル名を指定して、その次に「Finish」を選ぶとファイルができあがります。

ウィザードから戻ると、作成したファイルが開かれているのでそのまま「Palette」からペタペタとElementを張り付けていきます。今回は、下記のようなものを作成してみました。

なお、iReportテンプレート中で式評価に使われる言語がなぜか「Groovy」になっているので、レポート全体の「Properties」から「Language」を「Java」に変更してください。
※もちろん、Javaで利用する場合は、です

貼り付けるElementで「Text Field」などの式評価が行えるものを選んだ場合は、テンプレート内で使用できる動的項目を出力することができます。

名前 意味 テンプレート中での表記 Report Inspector上での関連項目
パラメータ Javaプログラムから渡すパラメータ $P{パラメータ名} Parameters
フィールド データベースなどのリソースから取り込んだデータを出力する $F{フィールド名} Fields
変数 iReport内部で利用される変数 $V{変数名} Variables

静的な文字列は、Element「Static Text」を貼って、直接編集してください。また、上記の動的項目を使用する場合は、先に「Report Inspector上での関連項目」に記載の欄に使用する項目を追加しておかないと、テンプレートXMLのコンパイルでエラーになるので注意してください。例えば、パラメータを使用するなら「Parameters」を選んで、右クリックをしてから「Add Parameter」で追加します。

では、続いてJavaプログラムの方へ。ビルドにはsbtを使用しました。Scalaではないですけど、楽なもんでして…。
build.sbt

name := "jasperreports-example"

version := "0.0.1"

organization := "littlewings"

libraryDependencies ++= Seq(
  "net.sf.jasperreports" % "jasperreports" % "4.1.2",
  "com.itextpdf" % "itextpdf" % "5.1.2",
  "com.itextpdf" % "itext-asian" % "5.1.1"
)

一応、iTextAsianも入れているのですが、今回は日本語の使用はちょっと断念しました…。

テンプレートにバインドさせるデータモデル。主にパラメータ($P)で使用しますが、フィールド($F)に対応するListも保持しています。
PageMain.java

import java.util.List;
import java.util.ArrayList;

public class PageMain {
    private String title;
    private String name;

    private List<PageDetail> details = new ArrayList<PageDetail>();

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addDetail(PageDetail detail) {
        details.add(detail);
    }

    public void addDetail(String name, int price) {
        PageDetail detail = new PageDetail();
        detail.setName(name);
        detail.setPrice(price);
        addDetail(detail);
    }

    public List<PageDetail> getDetails() {
        return details;
    }
}

フィールドに対応するクラス。
PageDetail.java

public class PageDetail {
    private String name;
    private int price;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getPrice() {
        return price;
    }
}

あとは、メインクラスで各種インスタンスを生成してバインドします。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.data.JRMapCollectionDataSource;

public class JasperReportsExample {
    public static void main(String[] args) {
        try {
            JasperReport jasperReport = JasperCompileManager.compileReport("pdf/input/sample_report1.jrxml");

            PageMain pageMain = new PageMain();
            pageMain.setTitle("main title");
            pageMain.setName("test");
            pageMain.addDetail("product1", 300);
            pageMain.addDetail("product2", 500);

            @SuppressWarnings("unchecked")
            JasperPrint print = JasperFillManager.fillReport(jasperReport,
                                                             BeanUtils.describe(pageMain),
                                                             new JRBeanCollectionDataSource(pageMain.getDetails()));

            JasperExportManager.exportReportToPdfFile(print, "pdf/output/sample_report1.pdf");
        } catch (Exception e) {
            e.printStackTrace();
        }
   }
}

今回は、データソースにJRBeanCollectionDataSourceを使用しました。いちいち本気のデータベースを持ってくるのが面倒だったものですので…。JavaBeansを作ったものの、BeanUtilsですぐにMapに変換しているので、あんまりPageMainクラスを用意した意味なかったかも…。

できあがったPDFはこちらです。

一応、ちゃんと生成できております。

それにしても、JasperReportsの情報って書籍とかでは滅法情報がないですね。少し前に出たこの本くらいじゃないでしょうか?まともに解説してるのって。

現場で使えるJavaライブラリ

現場で使えるJavaライブラリ