目次
Java プログラムから PDF を出力する
■PDF の出力に必要な JAR ファイルをダウンロード・配置
以下をダウンロードします。
- JasperReports Library (jasperreports-x.x.x-project.zip)
解凍したフォルダー内の、以下の 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 フォルダーの中身は、こんな感じ。
■プログラムを作る
Tomcat プロジェクトにサーブレット クラスを 1 つ追加します。ここでは、クラス名を「CreatePdfReportServlet」としました。クラスの追加先のパッケージは適当に。
以下のように記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
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) { // 省略 } } } |
プログラムの内容は意外と簡単です。
- 帳票レイアウト ファイルをコンパイルします。その結果は、JasperReport クラスのインスタンスになります。
- 帳票に埋め込むパラメーターを作成します。
- 帳票に埋め込むデータを取得するためのデータ ソースを作成します。今回の場合、JRCsvDataSource クラスのインスタンスになります。
- 1 で作成したコンパイル済み帳票レイアウト、2 で作成したパラメーター、3 で作成したデータ ソースを使って、帳票を作成します。その結果は、JasperPrint クラスのインスタンスになります。
- 4 を使って、PDF を出力します。
帳票レイアウト ファイルを動的にコンパイルする方法とは別に、前もってコンパイル済みの帳票レイアウト ファイルを準備しておき、実行時にロードする方法もあるので、ついでに実装してみました。コンパイルが不要な分、パフォーマンス的にはこちらの方が有利です。ただ、この方法で PDF 出力したら、文字の右揃えが適用されなかった…。なして?
JRCsvDataSource クラス以外にも、データベース用のクラスとか、いろいろ用意されています。また、JRDataSource インターフェイスを実装するクラスを実装して、独自のデータ形式を扱えるようにするのも、ちょっと楽しいかも。
JasperReport の API のリファレンスは、こちら。
■出力結果をブラウザーで確認
ブラウザーでサーブレットにアクセスして、PDF の出力結果を確認します。
一応出力はされている様子ですが、日本語が表示されていないという残念な結果に。どうやら、日本語のフォントを出力する設定が必要なようです。
ところで、PDF で日本語を表示するには、日本語フォントを埋め込まない方法と、埋め込む方法があります。それぞれメリット、デメリットがありますので、状況に応じて使い分ける必要があります。