竹形誠司 ブログ
Java+MySQL+Tomcat    »トピック一覧
掲示板へのスパムが多いため、「ご質問」のコーナーはユーザー登録制とさせていただきました。お手数ですが、上の「新規ユーザーの登録」メニューより登録をお願いします。
帳票Web
アプリケーション

受注開発始めました
詳しくは こちら
竹形 誠司 著/ラトルズ刊
JSP帳票アプリケーション実践開発入門
JSP帳票アプリケーション
実践開発入門

JSP業務アプリケーション短期開発入門
JSP業務アプリケーション
短期開発入門

Java+MySQL+Tomcatで始めるWebアプリケーション構築入門
Java+MySQL+Tomcatで始めるWebアプリケーション構築入門

Java+MySQL+Tomcatで作る掲示板とブログ
Java+MySQL+Tomcatで作る
掲示板とブログ
サーバサイドでPDFデータを印刷
by 竹形 誠司[takegata]
大量の帳票印刷への対応
最近、PDFで帳票を出力するサーバアプリケーションについての本を書き始めました。主に、「サーバ側でデータベースなどを参照して動的にPDFを生成し、ブラウザに返す」という使い方を想定していますが、毎日大量の帳票を出力する業務などでは、その都度ブラウザから印刷を操作するのでは手間がかかり過ぎるという場合もあるでしょう。そこでサーバサイドで印刷する方法についていろいろ調べてみました。

AcrobatまたはAdobeReader
AcrobatやAdobeReaderをコマンドラインから実行して指定したファイルを印刷できるようです。

http://kb2.adobe.com/jp/cps/510/510705.html

しかし、環境に依存しそうですし、せっかくなのでJavaで書ける方法を探しました。

Java 印刷サービス
J2SEに標準の「Java 印刷サービス」が使えるかどうか試してみました。

http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/jps/spec/jpsOverview.fm4.html

このページのサンプルコードはそのままではコンパイルできないので、いろいろ修正を加えて次のようなコードを書きました。

import javax.print.attribute.standard.Sides;
//以下 import 略

public class PdfPrintTest{

    public static void main(String[] args){
        FileInputStream textStream=null;
        try {
            textStream = new FileInputStream("Test.pdf");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (textStream == null) {
            return;
        }
        DocFlavor myFormat = DocFlavor.INPUT_STREAM.PDF;
        Doc myDoc = new SimpleDoc(textStream, myFormat, null);
        PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
        aset.add(new Copies(1));
        aset.add(MediaSizeName.ISO_A4);
        aset.add(Sides.DUPLEX);
        PrintService service = PrintServiceLookup.lookupDefaultPrintService();
        DocPrintJob job = service.createPrintJob();
        try {
            job.print(myDoc, aset);
            System.out.println("test1");
        } catch (PrintException e) {
            e.printStackTrace();
        }
    }
}
しかし、このコードを実行するとinvalid flavorというエラーが出てしまいます。DocFlavor.INPUT_STREAM.PDF を指定するには、PDF出力に対応したプリンタ(およびプリンタドライバ)を使う必要があるようです。

PDFBox
ApacheにPDFBoxというPDF処理ライブラリのプロジェクトがあります。

http://pdfbox.apache.org/download.html

ここで公開されているバイナリをダウンロードしてみました。このライブラリには、コマンドラインからそのまま実行できるコマンドも含まれていました。次のようなコマンドでPDFファイルを印刷できます。

> java -jar pdfbox-app-1.5.0.jar PrintPDF -silentPrint Test.pdf
一応印刷はできましたが、日本語のメトリック(文字幅の情報)がライブラリの中に含まれていないので文字間隔がだいぶ空いてしまいます。この問題はPDFを生成する際にフォントを埋め込むことで対処できるようです。

ウェブアプリケーションでも使いやすいように、次のようなラッパーを書いてみました。

import java.awt.print.PrinterJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import org.apache.pdfbox.pdmodel.PDDocument;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.awt.print.PrinterException;

public class PdfPrint{

    public static void main(String[] args){
        if(args.length!=1){
            System.out.println("no pdf file specified");
        }
        try{
            InputStream stream = new FileInputStream(args[0]);
            print(stream);
        }catch(FileNotFoundException e){
            System.out.println("file not found");
        }
    }

    public static void print(InputStream is){
        try{
            PDDocument document = PDDocument.load(is);
            PrinterJob printJob = PrinterJob.getPrinterJob();
            PrintService service = PrintServiceLookup.lookupDefaultPrintService();
            printJob.setPrintService(service);
            document.silentPrint( printJob );
            document.close();
        }catch(IOException e){
            e.printStackTrace();
        }catch(PrinterException e){
            e.printStackTrace();
        }
    }
}
まだ試していませんが、サーバサイドで生成したPDFのOutputStreamをInputStreamに変換してprintメソッドに渡せばサーバアプリケーションで動的に生成したPDFデータを直接プリンタに送ることができると思います。たとえば、ショッピングサイトなどで、購入の決済処理と同時に帳票を印刷することができます。
投稿:竹形 誠司[takegata]/2011年 05月 24日 02時 12分 /更新:2011年 05月 24日 02時 16分