iTextを用いたPDFファイルの作成

更新日 2003/1/31


1. はじめに
 今まで私は印刷について不勉強で、java.printなどの仕様についてもやろうやろうとは思いつつも、どうもとっつき悪く、必要に迫られることがないこともあって、手付かずの領域でした。そんなおり、2002年10月に出版されたWEB+DB vol.11(技術評論社) で、フリーソフトで帳票作成という記事を見つけ、サンプルプログラムを見てこれは出来そうだぞと思い、実験するに至りました。ここでは、Java環境での日本語によるPDFファイルの出力を実践し、最終的にはサーブレットとして帳票をブラウザに送り込むようなプログラムを作ってみたいと思います。
2. 準備
3. 日本語の表をファイルに出力
4. サーブレットによるWebブラウザからの印刷
2. 準備 ↑top
 まずは、環境を揃えるとしましょう。JDKが要りますので、まだインストールされていない方は、 こちら を参照してください。今回利用するiTextというフリーソフトは、JDK1.2以降で使用可能ということで、今であればJDK1.4ということになるでしょう。

  iTextは、iText.jar と言う形で、提供されており、 ここ から取得できます。FTPまたはHTMLのCompled code のところの jar1(PDF/THML)をクリックしてください。それと、日本語のフォントを扱うために、 iTextAsian.jar もダウンロードします。説明は、 ここ の下の方にあります。

  これを、適当なフォルダに収容し、クラスパスを張ってください。

 私の環境では、C:\j2sdk1.4.0配下に置いたので、Windows2000のシステム環境変数に以下のように設定しています。

 変数   CLASSPATH
  値       .;C:\j2sdk1.4.0\iText.jar;C:\j2sdk1.4.0\iTextAsian.jar
. は、今いるフォルダにあるクラスを起動するために入れていますが、必要なのは、C:\j2sdk1.4.0\iText.jar 以下の方です。
iText.jar や iTextAsian.jar の置き場に合わせて変更してください。

3. 日本語の表をファイルに出力 ↑top

 いきなりですが、日本語を含む表をPDF出力するサンプルプログラムを作ってみましょう。この動作確認ができてしまえば、これを応用してたいていの帳票は作れそうな気がします。とりあえず、以下のプログラムをHanakotoba.javaと言う名のファイルに入れて、javac Hanakotoba.java としてコンパイルし、java Hanakotoba で実行すると同じフォルダに Hanakotoba.pdf というファイルが出力され、これをAcrobatReaderで読むと、表の中にちゃんと日本語が表示されているはずです。

import java.io.FileOutputStream;
import java.io.IOException;
import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.pdf.BaseFont;

public class Hanakotoba{

private static String flowers[] = { "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","リンドウ","悲しんでいる時のあなたが大好き"};

public static void main(String[] args) {
System.out.println("Hanakotoba.pdfを生成します...");

// Documentオブジェクトの生成
//    A4縦は、 Document document = new Document(PageSize.A4);
//    A4横は、Document document = new Document(PageSize.A4.rotate());


Document document = new Document();    

try {

/*PdfWriterオブジェクトの生成*/
PdfWriter.getInstance(document, new FileOutputStream("Hanakotoba.pdf"));

/*ドキュメントのOPEN*/
document.open();

/*コンテンツの記述*/

// Font の指定  以前、以下2つの設定で、エラーになるという説明にしていましたが、iTextAsian.jar を併用することで
//   解消されました。 多田さん、ご指摘ありがとうございました。


// 明朝体っぽい字体なら以下を設定します。
BaseFont bf = BaseFont.createFont("HeiseiMin-W3", "UniJIS-UCS2-HW-H",false);

// ゴシックっぽい字体なら以下の設定にします。
// BaseFont bf = BaseFont.createFont("HeiseiKakuGo-W5", "UniJIS-UCS2-H",false);

// この他、WindowsのMSゴシックを使う場合は、以下のようにします。
// BaseFont bf = BaseFont.createFont("c:\\winnt\\fonts\\msgothic.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED)
;

Font font = new Font(bf, 12);

Paragraph para = new Paragraph("花言葉データ表",font);
para.setAlignment(Element.ALIGN_CENTER);
document.add(para);

Table aTable = new Table(3); //テーブル・オブジェクトの生成
aTable.setDefaultHorizontalAlignment(Element.ALIGN_CENTER);
aTable.setDefaultVerticalAlignment(Element.ALIGN_MIDDLE);
aTable.setPadding(2);

int width[] = {10,30,60};
aTable.setWidths(width); //各カラムの大きさを設定(パーセント)
aTable.setWidth(70); //テーブル全体の大きさを設定(パーセント)

aTable.addCell("No"); //カラム名
aTable.addCell("Flower"); //カラム名
aTable.addCell("Message"); //カラム名
aTable.endHeaders(); //頁をまたがってもカラム名を表示する

//花言葉の書込み
for(int i=0;i<flowers.length;i++){
Cell cell = new Cell(new Phrase(flowers[i],font));
int columnIndex = (i+1) % (aTable.columns()*2);
if ((columnIndex > aTable.columns()) || (columnIndex == 0)) {
cell.setGrayFill(0.9f); //グレーで塗りつぶす
}
aTable.addCell(cell);
}

document.add(aTable);

}catch(DocumentException de) {
System.err.println(de.getMessage());
}catch(IOException ioe) {
System.err.println(ioe.getMessage());
}catch(Exception e){
System.err.println(e.getMessage());
}

/*ドキュメントのCLOSE*/
document.close();
}
}

4. サーブレットによるWebブラウザからの印刷  ↑top

 今度は、サーブレットの例です。サーブレットでは、PDFファイルを出力するというよりは、ContextTypeをpdfで指定して、ブラウザに向かってPDF形式で出力する形になります(下記プログラムを参照)。ブラウザ側では、AcrobatReaderのプラグインが起動し、画面内にPDFファイルが表示されます。ここでは、PostgreSQLへのデータベース検索結果を表示するようにしていますが、出力は、 こんな感じ になります。

res.setContentType("application/pdf");
PdfWriter.getInstance(document, res.getOutputStream());



【サーブレットのコンパイル】
 TOMCAT環境でのコンパイル手順を以下に示します。
@iText.jar と iTextAsian.jar と pgjdbc2.jarは、C:\jakarta-tomcat-3.3.1\lib\apps\ に置く。

Ac:\jakarta-tomcat-3.3.1\bin\tomcat.bat に以下のスタティッククラスパスを追加
if exist "%TOMCAT_HOME%\lib\apps\iText.jar" set CLASSPATH=%CLASSPATH%;%TOMCAT_HOME%\lib\\apps\iText.jar
if exist "%TOMCAT_HOME%\lib\apps\iTextAsian.jar" set CLASSPATH=%CLASSPATH%;%TOMCAT_HOME%\lib\\apps\iTextAsian.jar
if exist "%TOMCAT_HOME%\lib\apps\pgjdbc2.jar" set CLASSPATH=%CLASSPATH%;%TOMCAT_HOME%\lib\\apps\pgjdbc2.jar

Bコマンドプロンプトにて、c:\jakarta-tomcat-3.3.1\bin\tomcatEnv.bat を実行する。

Cサーブレット(dbSearch.java)をコンパイルします。dbSearch.java は、C:\jakarta-tomcat-3.3.1\webapps\examples\WEB-INF\classes配下においてみました。
cd C:\jakarta-tomcat-3.3.1\webapps\examples\WEB-INF\classes
javac dbSearch.java

【実行】
PostgreSQLを起動し、Tomcatを起動してから、以下のURLを指定することで、ブラウザがAcrobatReaderのプラグインを呼び出して画面内にPDFファイルが表示されます。
http://localhost/examples/servlet/dbSearch/


サンプルプログラム dbSearch.java
 PDF出力に関連するところを青色で示します。

import java.io.*;
import java.util.Date;
import java.awt.Color;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Vector;
import java.util.Enumeration;
import java.text.DateFormat;
import java.sql.*;
import javax.servlet.http.*;
import javax.servlet.*;
import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.rtf.RtfWriter;
import com.lowagie.text.pdf.BaseFont;


public class dbSearch extends HttpServlet {
private static String db_url = "jdbc:postgresql:Administrator";
private static String db_user = "Administrator";
private static String db_password = "";
private Connection conn =null;
private static Font small_font = new Font(Font.HELVETICA,8);

DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.MEDIUM, Locale.JAPAN);


public void init(ServletConfig config) throws ServletException {
super.init(config);
//タイムゾーンの指定
df.setTimeZone(TimeZone.getTimeZone("JST"));

try {
// JDBCドライバのローディング
Class.forName("org.postgresql.Driver");

// DBに接続する
conn = DriverManager.getConnection(db_url, db_user, db_password);

} catch (ClassNotFoundException e){
System.err.println("JDBCドライバが見つかりません");
} catch(SQLException e){
System.err.println("DBの接続に失敗しました。エラー内容: " + e);
}
}

protected void processRequest(HttpServletRequest req, HttpServletResponse res)
throws ServletException, java.io.IOException {

//リクエスト・パラメータ(SQL条件分)を取得
String sql_param = req.getParameter("sql_param");

//ドキュメント・オブジェクトの生成
Document document = new Document(PageSize.A4, 20, 20, 40, 36);



try {
res.setContentType("application/pdf");
PdfWriter.getInstance(document, res.getOutputStream());


//ドキュメントのOPEN
HeaderFooter header = new HeaderFooter(new Phrase(df.format(new Date())), false);
HeaderFooter footer = new HeaderFooter(new Phrase("page "), new Phrase("."));
footer.setAlignment(Element.ALIGN_CENTER);
document.setHeader(header);
document.setFooter(footer);
document.open();


//コンテンツの生成
Table datatable = getTable(sql_param);
document.add(datatable);


}catch(DocumentException de){
System.err.println(de.getMessage());
}catch(Exception e){
System.err.println(e.getMessage());
}

//ドキュメントのCLOSE
document.close();
}

protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, java.io.IOException {
processRequest(req, res);
}

protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, java.io.IOException {
processRequest(req, res);
}

private Table getTable(String sql_param) throws BadElementException, DocumentException, IOException {

//テーブルの基本設定
Table aTable = new Table(4);
aTable.setDefaultHorizontalAlignment(Element.ALIGN_CENTER);
aTable.setDefaultVerticalAlignment(Element.ALIGN_MIDDLE);
aTable.setPadding(2);
aTable.setSpacing(0);
int widths[] = {4,10,43,43};
aTable.setWidths(widths);
aTable.setWidth(93);


//ヘッダー設定
BaseFont bf = BaseFont.createFont("c:\\winnt\\fonts\\msgothic.ttc,1",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font font = new Font(bf, 8);
Cell cell = new Cell(new Phrase("検 索 結 果", font));
cell.setColspan(4);
cell.setBackgroundColor(new Color(0xC0, 0xa0, 0xC0));
aTable.addCell(cell);
aTable.addCell(new Phrase("項番",font));
aTable.addCell(new Phrase("郵便番号",font));
aTable.addCell(new Phrase("住所",font));
aTable.addCell(new Phrase("住所(半角カナ)",font));
aTable.endHeaders();


//データの格納
aTable.setDefaultHorizontalAlignment(Element.ALIGN_LEFT);
for(Enumeration e = getContents(sql_param).elements();e.hasMoreElements();){
aTable.addCell(new Phrase((String)e.nextElement(), font));
}

return aTable;
}

private Vector getContents(String sql_param){
Vector contents = new Vector();

try{
// ステートメントの作成
Statement stmt = conn.createStatement();

String sql = "select * from yuubin where zipcode like '2850%' order by zipcode";
// String sql = "select * from yuubin where zipcode like " + sql_param + " order by zipcode";

ResultSet rs = stmt.executeQuery(sql);
ResultSetMetaData meta = rs.getMetaData();

//表のセルに対応するデータを整列して格納
long row_count = 1;
while (rs.next ()) {
for (int i=0; i < meta.getColumnCount(); i++) {

//行数のカウントと記録
if(i==0){
contents.addElement(Long.toString(row_count));
row_count++;
}

//データの抽出と格納
Object cell_obj = rs.getObject(i+1);
contents.addElement(cell_obj.toString());
}
}
rs.close(); rs = null;
stmt.close(); stmt = null;
} catch (Exception e){
System.err.println("DB処理に問題がありました(" + e + ")");
}
return contents;
}
}






[HOME] / [Perl] / [Oracle8] / [Palm(GCC)] / [Palm(CodeWarrior)] / [EJB] / [本の紹介]

このページにご意見のある方は、egami@ee.e-mansion.com までお願い致します。