5
10

More than 3 years have passed since last update.

Servlet + JasperReports で動的に PDF を作成して Web サイトに表示してみるメモ

Last updated at Posted at 2020-12-06

先日、Servlet + Apache FOP ネタ とか その続編 とか投稿したのですが、知り合いから「Jasper 良さげだよ」との情報をいただきまして。ググったら情報多い!主流はコッチだったか… と。

既に日本語の情報は十分にある気もするので、備忘録として、簡単な実施メモにまとめてみました。

JasperReports 概要

まず Jasper 系の PDF (帳票) 生成に関して、以下が理解の助けになりました。

以下は公式もしくはダウンロードサイト。

LGPL のようですが、一応はライセンス周りを確認。

Jaspersoft StudioプラグインをEclipseにインストール

iReportはjdk1.8に対応していない らしいので、今回は Jaspersoft Studio の Eclipse 用プラグインを利用してみます。

私の今のテスト環境 Eclipse 2020-09 で「Help -> Eclipse Marketplace」から Jaspersoft 6.16.0 をインストール。
image.png
ここで同意するライセンスは Eclipse Foundation Software User Agreement のみの模様。
image.png
インストール後は Eclipse が再起動するので、Welcome 画面に以下のような表示があればok。
image.png
後は新規作成メニューに追加された「Jasper Report」を新規作成すれば
image.png
テンプレートの選択画面が出てきて、
image.png
そして、こんな感じの帳票のデザイン画面が開きます。
image.png

開発環境の準備

今回の開発環境はこんな感じです。
image.png

1) お馴染みのデータ入力用のシンプルな html ページ
2) 今回の主役、PDF を自動生成する Servlet
3) 先ほどインストールした Jaspersoft Studioプラグインで作成したテンプレート
4) 開発時に必要な JasperReports Library 用 jar ファイル
5) Servlet 実行時に必要な JasperReports Library 用 jar ファイル

4) ですが Jaspersoft Studioプラグインをインストール時に Eclipse に登録されていますので、ビルドパスへライブラリを追加します。
image.png
5) もプラグインをインストールしてあればPC内にあるはずなので、探して WEB-INF/lib 下にコピーもしくはリンクします。MVN リポジトリ JasperReports Library から入手してもかまいません。なお ipaexm.jar に関してはこの後で説明します。

フォント設定

こちら の情報をもとに 「IPAex明朝」フォントをダウンロードし設定します。
image.png
ここで大事なのは PDF Encoding 欄で Identity-H(Unicode with horizontal writing) を選択することです。これを忘れると日本語が出力されません。

フォントの設定が終わったら、一覧メニューで「Export」を実行します。
image.png
jar ファイルの保存画面になりますので WEB-INF/lib 下に ipaexm.jar というファイル名で保存します。これで開発環境で指定したフォント設定を、Servlet 実行環境に反映することができました。

PDF テンプレートを作成する

Jaspersoft Studioプラグインで PDF テンプレートを作成します。今回は以下のようにシンプルなもので試しましょう。
image.png

1) は単純にタイトルを表示しているだけです。Static Text を配置して、適当なタイトルを入力し、さきほど設定した日本語フォントを指定します。
image.png

2) は Current Date を配置しただけです。日本語ではありませんが、表示を統一するためフォントだけ指定します。
image.png

3) が動的に設定するテキストになり、最も大事な部分です。まず右の要素ツリーで MY_MESSAGE という名称の独自パラメーターを追加します。
image.png
指定する名称と型(今回は文字列)は以下のような感じ。
image.png
次に Text Field 要素を追加します。表示内容を指定する Expression Editor では追加した独自パラメーターの MY_MESSAGE を選択します。あ、フォント指定もお忘れなく。
image.png

さて、これでテンプレートは完成しました。以下はプレビューを実行した様子です。
image.png

保存した sample1.jrxml ファイルは以下のような感じ。

sample1.jrxml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.16.0.final using JasperReports Library version 6.16.0-48579d909b7943b64690c65c71e07e0b80981928  -->
<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="sample1" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="3fe7289f-d8d2-4a65-9b55-c9aa20be3391">
    <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
    <parameter name="MY_MESSAGE" class="java.lang.String" isForPrompting="false"/>
    <queryString>
        <![CDATA[]]>
    </queryString>
    <background>
        <band splitType="Stretch"/>
    </background>
    <title>
        <band height="79" splitType="Stretch">
            <staticText>
                <reportElement x="80" y="20" width="400" height="30" uuid="b771d8a0-efcc-4c72-a8eb-f66f1b7bc644"/>
                <textElement textAlignment="Center">
                    <font fontName="IPAex明朝" size="16"/>
                </textElement>
                <text><![CDATA[JasperReports PDF サンプル]]></text>
            </staticText>
        </band>
    </title>
    <pageHeader>
        <band height="49" splitType="Stretch">
            <textField pattern="MMMMM dd, yyyy">
                <reportElement x="370" y="10" width="180" height="30" uuid="cf6034bc-e2c5-4db9-806d-e40ed1bc65a5"/>
                <textElement textAlignment="Right">
                    <font fontName="IPAex明朝"/>
                </textElement>
                <textFieldExpression><![CDATA[new java.util.Date()]]></textFieldExpression>
            </textField>
        </band>
    </pageHeader>
    <columnHeader>
        <band height="61" splitType="Stretch"/>
    </columnHeader>
    <detail>
        <band height="125" splitType="Stretch">
            <textField>
                <reportElement x="0" y="10" width="550" height="100" uuid="0298349c-4284-4697-b6ad-792637b8e76e"/>
                <textElement>
                    <font fontName="IPAex明朝"/>
                </textElement>
                <textFieldExpression><![CDATA[$P{MY_MESSAGE}.toString()]]></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>

保存した sample1.jrxml ファイルを右クリックメニューからコンパイルし、sample1.jasper ファイルを生成しておきます。
image.png

入力用ページ

入力用ページは これまでと同じ ですので、説明は省きますね。フォーム部分は以下のような感じ。

index.html
<div class="container">
    <h2>Simple JasperReports sample with Servlet</h2>
    <form method="POST" action="/test03/pdfServlet">
        <div class="form-group">
            <label for="i_fname">Document format</label>
            <input type="text" class="form-control" id="i_fname" name="i_fname" value="sample1">
            <label for="i_body">Body mwssage</label>
            <input type="text" class="form-control" id="i_body" name="i_body" value="Sample body text...">
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>
</div>

Servlet

さて、今回のコアとなる Servelt 部分ですが、実は過去の Apache FOP 版 とあまり変わらなかったりします。呼び出しているライブラリが異なるぐらい?実際のコードを見てもらったほうが理解し易いとおもいます。

pdfServlet.java
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperRunManager;

@WebServlet("/pdfServlet")
public class pdfServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public pdfServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            request.setCharacterEncoding("utf-8");
            String i_fname = request.getParameter("i_fname");
            String i_body = request.getParameter("i_body");
            File jasperFile = new File(getServletConfig().getServletContext().getRealPath("/" + i_fname + ".jasper"));
            HashMap<String, Object> params = new HashMap<String, Object>();
            params.put("MY_MESSAGE", i_body);
            byte[] bytes = JasperRunManager.runReportToPdf(jasperFile.getPath(), params, new JREmptyDataSource());
            response.setContentType("application/pdf");
            response.setContentLength(bytes.length);
            response.setHeader("Content-Disposition", "inline");
            ServletOutputStream out = response.getOutputStream();
            out.write(bytes);
            out.flush();
        } catch (Exception ex) {
            throw new ServletException(ex);
        }
    }

}

ポイントは params.put("MY_MESSAGE", i_body); ですね。PDF テンプレートを作成した際に設定した独自パラメーターに対し、表示用の値をここで渡してあげるわけです。

今回はテンプレートをファイルから読み込んでいますが、DB 化については 続編のほう を参照してみてください。コンパイル後はバイナリ形式であることに留意すれば、ほぼ同じ考え方で対応できるとおもいます。

実行してみよう

さて、まずはいつものように index.html を開いてテキストを入力し、
image.png
「Submit」で入力したテキストが埋め込まれた PDF が表示されることを確認します。
image.png
うん、問題なさそうですね。日本語のタイトルも、今日の日付も表示されています。そして本文の部分には、フォームで入力した日本語を含んだテキストが、ちゃんと埋め込まれているのを確認できました。

生成された PDF について

今回のサンプルプログラムで生成した PDF ファイルを以下の URL に置きました。

いまのところ、以下の環境で表示の確認をしています。もし文字化けとかしちゃう環境などありましたら、コメントいただけると助かります!

  • Google Chrome on Windows 10
  • Edge on Windows 10 (IEで開いてもこちら起動する)
  • Safari on Mac
  • Safari on iPhone
  • Kindle Fire HD (Silk ブラウザで表示するとKindleアプリが起動し表示)

ライセンス

この投稿に含まれる私の作成した全てのコードは Creative Commons Zero ライセンス とします。自由にお使いください。

おまけ:表示・非表示をコントロールする

PDFで表を生成するサンプルを作成したところ「データが無い場合、ヘッダだけの空の表はみっともない。この場合は表自体を非表示にできないか」という相談がありました。こんな場合に使えるのが、各要素にある Print When Expression 欄です。
image.png
ここに式を書いておくと、その式が true の場合にその要素が表示されます。false であれば非表示です。例えば今回のサンプルでメッセージの表示欄に以下のような式を設定してみると
image.png
10文字以下の短いメッセージを入力すると、PDFに表示されなくなります。

表に使用する場合は、表自体、もしくは表を含むセクション全体の Print When Expression 欄に、表示行数を参照する条件演算子を設定すると良さそうです。

Enjoy!

以上、Servlet を用いて Web サイトで、JasperReports を用いた PDF の動的生成を試してみました。これをベースに、いろいろ機能を追加して遊んでみてください。

Apache FOP も JasperReports も Servlet から使うぶんには、それほど違いがない気がします。でもテンプレートを作成する部分、JasperReports 用プラグインによる GUI ベースの設定は圧倒的に楽ですね。なので、JasperReports のほうを強く推したいとオモイマス。

それではまた!

5
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
10