JasperReports 6 で PDF を作り、ブラウザーで表示する【3】

JasperReport 6 と Java を使って PDF を出力しました。試行錯誤の連続だったので、忘れないように、一連の手順をまとめました。今回は「【3】Java プログラムから PDF を出力する」です。

← 前回:【2】帳票レイアウトを作成する

JAR ファイルをダウンロード・配置する

PDF の出力に必要な JAR ファイルをダウンロードします。

展開したフォルダー内の以下の JAR ファイルを、Tomcat プロジェクトの lib フォルダーに配置します。これらは、本文内のプログラムを動作させるために、最低限必要と思われる JAR ファイルたちです。
また、一部の JAR ファイルについては、プログラムのビルド時にも参照されるので、Eclipse のビルドパスに追加します。

JAR ファイル名 ビルドパスに追加 ファイルの入手元
jasperreports-x.x.x.jar jasperreports-x.x.x-project\dist
jasperreports-fonts-x.x.x.jar
jasperreports-javaflow-x.x.x.jar
commons-beanutils-x.x.x.jar jasperreports-x.x.x-project\lib
commons-collections-x.x.x.jar
commons-digester-x.x.jar
commons-logging-x.x.x.jar
itext-pdfa-x.x.x.jar
itextpdf-x.x.x.jar

lib フォルダーの中身は、次のようになりました。

[Eclipse] JAR ファイルを配置
JAR ファイルを配置

プログラムを作る

Tomcat プロジェクトにサーブレット クラスを 1 つ追加します。ここでは、クラス名を「CreatePdfReportServlet」としました。クラスの追加先のパッケージは適当に。

[Eclipse] HttpServlet を継承したクラスを追加
HttpServlet を継承したクラスを追加
package com.tk2kpdn.study.project001;

import java.io.PrintWriter;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRCsvDataSource;
import net.sf.jasperreports.engine.util.JRLoader;

public class CreatePdfReportServlet extends HttpServlet
{
    private static final long serialVersionUID = 1L;

    /**
     * 帳票レイアウト ファイルのパス。
     */
    private static final String JRXML_FILE_PATH = "/WEB-INF/resources/reports/SushiMenuReport.jrxml";
  
    /**
     * コンパイル済み帳票レイアウト ファイルのパス。
     */
    private static final String JASPER_FILE_PATH = "/WEB-INF/resources/reports/SushiMenuReport.jasper";
    
    /**
     * 帳票に表示する CSV ファイルのパス。
     */
    private static final String CSV_FILE_PATH = "/WEB-INF/resources/data/SushiMenuData.csv";
    
    /**
     * 動的にコンパイルされた帳票レイアウトを作成します。
     * @return 動的にコンパイルされた帳票レイアウト。
     * @throws JRException
     */
    private JasperReport createLazyCompiledReport() throws JRException
    {
        ServletContext servletContext = this.getServletConfig().getServletContext();
        
        File jrxmlFile = new File(servletContext.getRealPath(CreatePdfReportServlet.JRXML_FILE_PATH));
        
        // 帳票レイアウトをコンパイルします。
        JasperReport jasperReport = JasperCompileManager.compileReport(jrxmlFile.getPath());
        
        return jasperReport;
    }
    
    /**
     * 静的にコンパイルされた帳票レイアウトを作成します。
     * @return 静的にコンパイルされた帳票レイアウト。
     * @throws JRException
     */
    private JasperReport createPreCompiledReport() throws JRException
    {
        ServletContext servletContext = this.getServletConfig().getServletContext();
        
        File jasperFile = new File(servletContext.getRealPath(CreatePdfReportServlet.JASPER_FILE_PATH));

        // コンパイル済み帳票レイアウトをロードします。
        JasperReport jasperReport = (JasperReport)JRLoader.loadObject(jasperFile);
        
        return jasperReport;
    }
    
    /**
     * 帳票レイアウトに設定するためのパラメーターを作成します。
     * @return 帳票レイアウトに設定するためのパラメーター。
     */
    private Map<String, Object> createParameters()
    {
        HashMap<String, Object> parameters = new HashMap<String, Object>();
        
        parameters.put("REPORT_CATCHPHRASE", "美味しいよ!");
        
        return parameters;
    }
    
    /**
     * 帳票レイアウトにバインドするためのデータ ソースを作成します。
     * データ ソース内にデータの読み込み状況を保持しているっぽいので、複数の帳票作成で使いまわすことはできない様子。
     * @return 帳票レイアウトにバインドするためのデータ ソース。
     * @throws JRException
     */
    private JRDataSource createDataSource() throws JRException
    {
        ServletContext servletContext = this.getServletConfig().getServletContext();
        
        File csvFile = new File(servletContext.getRealPath(CreatePdfReportServlet.CSV_FILE_PATH));
        
        JRCsvDataSource dataSource = new JRCsvDataSource(csvFile.getPath());
        
        // 1 行目をヘッダー (フィールド名) として扱います。
        dataSource.setUseFirstRowAsHeader(true);
        
        return dataSource;
    }
    
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {
        try
        {
            // 帳票レイアウト ファイル (.jrxml) を実行時に動的にコンパイルし、帳票を作成します。
            JasperPrint jasperPrint = JasperFillManager.fillReport(
                this.createLazyCompiledReport(), this.createParameters(), this.createDataSource());

            // コンパイル済み帳票レイアウト ファイル (.jasper) から、帳票を作成します。
            // JasperPrint jasperPrint = JasperFillManager.fillReport(
            //     this.createPreCompiledReport(), this.createParameters(), this.createDataSource());
            
            byte[] bytes = JasperExportManager.exportReportToPdf(jasperPrint);

            response.setContentType("application/pdf");
            response.setContentLength(bytes.length);

            ServletOutputStream out = response.getOutputStream();
            out.write(bytes);
            out.flush();
            out.close();
        }
        catch (Exception e)
        {
            // 省略
        }
    }
}

長いプログラムなのですが、内容は意外と簡単です。

  1. 帳票レイアウト ファイルをコンパイルします。その結果は、JasperReport クラスのインスタンスになります。
  2. 帳票に埋め込むパラメーターを作成します。
  3. 帳票に埋め込むデータを取得するためのデータ ソースを作成します。今回の場合、JRCsvDataSource クラスのインスタンスになります。
  4. 1 で作成したコンパイル済み帳票レイアウト、2 で作成したパラメーター、3 で作成したデータ ソースを使って、帳票を作成します。その結果は、JasperPrint クラスのインスタンスになります。
  5. 4 を使って、PDF を出力します。

JasperReport の API のリファレンスは、こちら。

出力結果をブラウザーで確認

ブラウザーでサーブレットにアクセスして、PDF の出力結果を確認します。

PDF の出力結果。日本語が表示されていない
PDF の出力結果。日本語が表示されていない

一応出力はされているのですが、日本語が表示されていないという残念な結果になってしまいました。日本語のフォントを出力する設定が必要なようです。

PDF で日本語を表示するには、日本語フォントを PDF に埋め込まない方法と、埋め込む方法があります。それぞれメリット、デメリットがありますので、状況に応じて使い分ける必要があります。

次回:【4】日本語が出力できるようにする ~PDF にフォントを埋め込まない編~ →

kpdn

お寿司とゲームと動物が好きな、フリーランスのエンジニアです。フロントエンドからインフラまで日々奮闘中です。最近は物忘れがどんどんがひどくなってきました。

コメントを残す