Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

JakartaPOIでExcel形式の帳票を出力する

POIライブラリによるExcel形式ファイルのダウンロード方法

  • LINEで送る
  • このエントリーをはてなブックマークに追加

Webシステムのデータ提供形式としてはCSVファイルが一般的ですが、罫線や計算式等を利用できるためExcelファイルでの提供要望も多くあります。そこで、ここではPOIと呼ばれるライブラリを用いてJavaからExcelファイルを出力する例を紹介します。

はじめに

 Webシステムでデータをダウンロードする場合、CSV形式が一般的ですが、Excel形式で出力したいという要望も良くあります。これは、罫線やフォントの変更など見栄えのよい帳票が作成できることや、Excelが表計算アプリケーションとしてエンドユーザに広く受け入れられているためだと思われます。そこで本稿ではJavaからExcelファイルを出力しダウンロードする方法を紹介します。サンプルでは、請求書番号を入力すると、Excelにて作成された請求書がダウンロードできるという機能を実装しています。

WebブラウザからExcelファイルをダウンロード
WebブラウザからExcelファイルをダウンロード

対象読者

 Javaプログラミングを行ったことがある、もしくは、Javaプログラミングに興味のある方を対象としています。

必要な環境

 このサンプルはJ2SE(TM) Development Kit 5.0 Update 2Tomcat5.5.7にて動作確認をしています。また、WebフレームワークのStruts1.2を使用していますが、サンプルソースに内包しているためJ2SDKとサーブレットコンテナ以外の環境は必要ありません。またExcelのインストールも必要ありません。環境についての詳細や設定方法については、「サーバサイド技術の学び舎 - WINGS」にある「サーバサイド環境構築設定」を参照してください。

サンプルアプリケーションの概要

 サンプルアプリケーションの流れは以下の通りです。

  1. ブラウザにて、ダウンロードボタンが押される。
  2. リクエストを受け取ったサーブレットコンテナにて、テンプレートとして用意したExcelファイルを読み込む。
  3. 請求書固有の情報をExcelファイルに書き込む。
  4. ブラウザにExcelファイルを出力(ダウンロード)する。
テンプレートとして用意したExcelファイル
テンプレートとして用意したExcelファイル

 タイトルや罫線など共通レイアウトは上図のようなテンプレートとしてあらかじめ作成しておき、顧客名称や金額といった請求書ごとに異なる値はプログラムから設定するようにします。レイアウトを動的に設定することも可能ですが、プログラムが複雑になってしまうのでテンプレートを作成しておくことを推奨します。

 なお、サンプルを実際に動作させてみたい場合には、記事上部のリンクから、ファイル「PoiExcel.war」をダウンロードしてTomcatなどのアプリケーションサーバの「webapps」フォルダに配置(デプロイ)してください。アプリケーションサーバ起動後に、「http://localhost:8080/PoiExcel」にアクセスすればサンプルを動作させることができます(ホスト名・ポート番号は読者の環境に合わせて変更してください)。

 また、今回のサンプルの主要ファイルは以下の通りです。

ファイル名概要
invoice.xlsテンプレートとなるExcelファイル。
Input.jspExcelをダウンロードする画面のJSPファイル。
InvoiceAction.javaStrutsのActionクラス。
InvoiceForm.javaStrutsのActionFormクラス。
InvoiceService.javaビジネスサービスを担当するクラス。
HeaderData.javaデータを保持するクラス(ヘッダー部)。
DetailData.javaデータを保持するクラス(明細部)。

POIとは

 JavaからExcelファイルの読込や更新を行うためには「POI」と呼ばれるライブラリを使用します。POIはExcelやWordといったMicrosoftOLE2ドキュメントを操作するAPIを提供しており、Jakartaプロジェクトにて開発が進められています。入手するにはJakartaのサイトからダウンロードできます。なお、今回のサンプルをコンパイルするためには「poi-2.5.1-final-20040804.jar」にクラスパスを通しておく必要があります。

Excelファイルのダウンロード処理

 それでは、ソースコードを見ながらアプリケーションの流れを見てみましょう。

リクエストの受付

入力画面
入力画面

 ブラウザから「Excel出力」ボタンを押下すると、StrutsのActionクラスのexecuteメソッドが実行されます。

「InvoiceAction.java」 抜粋
public class InvoiceAction extends Action {
    public ActionForward execute(ActionMapping mapping,
    ActionForm form, HttpServletRequest request,
    HttpServletResponse response) throws Exception {

        //請求書Noを元に請求書の詳細情報を取得し
        //「invoiceData」に設定します。
        InvoiceForm iForm = (InvoiceForm) form;
        InvoiceService iService = new InvoiceService();
        HeaderData invoiceData
            = iService.getInvoiceByInvoiceNo(iForm.getInvoiceNo());
        
     //(以下省略)

    }
}

 ここでは、StrutsのActionFormからリクエスト情報(請求書番号)を取り出し、ビジネスロジックにあたるInvoiceServiceクラスから請求書の詳細データを取得しています。この処理にてinvoiceDataオブジェクトに帳票出力用のデータが設定されます。

Excelファイルの読込・更新

 続いて以下のソースでは、Excelファイルの読込と更新を行っています。

「InvoiceAction.java」 抜粋
public class InvoiceAction extends Action {

    public ActionForward execute(ActionMapping mapping,
        ActionForm form, HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        
        //(中略)
        
        //テンプレートとなるExcelファイルのパスを取得します。
        final String INVOICE_FILE
            = "/WEB-INF/classes/to/msn/wings/invoice.xls";
        String filePath = this.getServlet()
            .getServletContext().getRealPath(INVOICE_FILE);
        //ファイルを読み込みます。
        POIFSFileSystem filein
            = new POIFSFileSystem(new FileInputStream(filePath));
        //ワークブックを読み込みます。
        HSSFWorkbook wb = new HSSFWorkbook(filein);
        //シートを読み込みます。
        HSSFSheet sheet = wb.getSheet("invoice");

        //行番号用の定数(縦)
        final int ROW_INVOICE_NO = 4;
        final int ROW_CUSTOMER_NAME = 6;
        final int ROW_DETAIL_START = 12;

        //列番号用の定数(横)
        final short COL_HEADER = 5;
        final short COL_DETAIL_GOODS_NAME = 3;
        final short COL_DETAIL_PRICE = 7;
        final short COL_DETAIL_COUNT = 8;
        final short COL_DETAIL_MEMO = 10;

        //請求書番号を設定します。
        HSSFRow row = sheet.getRow(ROW_INVOICE_NO);
        HSSFCell cell = row.getCell(COL_HEADER);
        cell.setEncoding(HSSFCell.ENCODING_UTF_16);
        cell.setCellValue(invoiceData.getInvoiceNo());

        //顧客名を設定します。
        row = sheet.getRow(ROW_CUSTOMER_NAME);
        cell = row.getCell(COL_HEADER);
        cell.setEncoding(HSSFCell.ENCODING_UTF_16);
        cell.setCellValue(invoiceData.getCustomerName());

        //明細行を設定します。
        Iterator it = invoiceData.getDetailList().iterator();
        int rowCount = 0;
        while (it.hasNext()) {
            row = sheet.getRow(ROW_DETAIL_START + rowCount);
            DetailData dd = (DetailData) it.next();
            
            //商品名の設定
            cell = row.getCell(COL_DETAIL_GOODS_NAME);
            cell.setEncoding(HSSFCell.ENCODING_UTF_16);
            cell.setCellValue(dd.getGoodsName());
            //cell.setCellStyle(styleB); 
            //価格の設定                
            cell = row.getCell(COL_DETAIL_PRICE);
            cell.setCellValue(dd.getPrice());
            //数の設定                
            cell = row.getCell(COL_DETAIL_COUNT);
            cell.setCellValue(dd.getCount());
            //摘要の設定                
            cell = row.getCell(COL_DETAIL_MEMO);
            cell.setEncoding(HSSFCell.ENCODING_UTF_16);
            cell.setCellValue(dd.getMemo());
            //次の明細行へ
            rowCount++;
        }

     //(以下省略)

    }
}

 ここでは、Excelファイルを読み込み、請求書固有の値(顧客名や明細データ等)を設定しています。POIではまずワークブックにアクセスし、それから、ワークシート→行→列→セルという順番にたどっていくことで目的のセルにアクセスすることができます。

POIの主要クラスとメソッド

 Excelファイルの読み込みと更新を行うための主要なクラスとメソッドは以下の通りです。

POIFSFileSystem

 POIFSFileSystemはExcelファイルを読み込む時に使用するクラスです。今回のサンプルでは特定の環境に依存しないように、パスを固定で埋め込まずServletContextgetRealPathメソッドを使用して相対的にパスを読み込むようにしています。

HSSFWorkbook

 HSSFWorkbookはワークブックを扱うクラスです。getSheetメソッドでシート名を指定してHSSFSheetオブジェクトを取得します。

HSSFSheet

 HSSFSheetはワークシートを扱うクラスです。getRowメソッドを用いて、特定の行(HSSFRowオブジェクト)を取得することができます。getRowメソッドの引数はint型で、0をベースとしているため1行目を取得したい場合は「0」を引数とします。

HSSFRow

 HSSFRowは行を扱うクラスです。getCellメソッドを用いて特定の行(HSSFCellオブジェクト)を取得することができます。getCellメソッドの引数はshort型で、0をベースとしているためA列を取得したい場合は「0」を引数とします。

HSSFCell

 HSSFCellはセルを扱うクラスです。setCellValueメソッドでセルの値に引数の文字列や数値を設定することができます。なお、文字列に日本語が含まれる場合には、事前にsetEncoding(HSSFCell.ENCODING_UTF_16)を呼び出しておく必要があります。

ダウンロードファイルの送信(レスポンス)

 ここでは、作成したExcelファイルをブラウザに送ります。

「InvoiceAction.java」 抜粋
public class InvoiceAction extends Action {
    public ActionForward execute(ActionMapping mapping,
        ActionForm form, HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        //(中略)

        //クライアントへのレスポンスを設定
        response.setHeader("Content-Disposition",
            "attachment;filename=invoice.xls");
        response.setContentType("application/vnd.ms-excel");
        wb.write(response.getOutputStream());

        //(中略)

        return null;
    }
}

 HSSFWorkbookクラスのwriteメソッドを呼び出してExcelファイルを出力しています。ここではHttpServletResponse#getOutputStreamメソッドによってServletOutputStreamを出力先に指定しています。

 また、ダウンロード用に渡されたデータであることをブラウザ側に伝えるためにHttpServletResponse#setHeaderメソッドにてヘッダ情報を設定しています。そして、コンテンツタイプ(MIME)をHttpServletResponse#setContentTypeメソッドにて設定しています。

 この一連の流れにて、Excelファイルのダウンロード処理が完成となります。

TIPS

 ここまでは、JavaからExcelを出力する方法を紹介しましたが、ここからはPOIを用いてプログラムをする上で便利なテクニックについて紹介します。

定数の利用

 Excelのプログラムでは列番号と行番号を数字で指定してセルを特定しますが、その数字をそのまま書いてしまうのは避けたほうが良いでしょう。これは、プログラムに埋め込まれた数字の意味がわからないために後々バグの原因になる可能性があるためです(「マジックナンバー」と呼ばれ可読性が低下します)。そのため、定数を宣言することを推奨します。

「InvoiceAction.java」 抜粋
    //行番号用の定数(縦)
    final int ROW_INVOICE_NO = 4;
    final int ROW_CUSTOMER_NAME = 6;
    final int ROW_DETAIL_START = 12;

    //列番号用の定数(横)
    final short COL_HEADER = 5;
    final short COL_DETAIL_GOODS_NAME = 3;
    final short COL_DETAIL_PRICE = 7;
    final short COL_DETAIL_COUNT = 8;
    final short COL_DETAIL_MEMO = 10; 

 なお、今回のサンプルでは「COL~」や「ROW~」で始まる定数名にて統一しています。これはEclipseのような統合開発環境を使っている場合、自動的に定数の候補が表示されるというメリットがあるためです。

Excelの設定(R1C1参照形式)

 通常、Excelの列の定義は「A~IV」というアルファベットで表示されていますが、Javaのプログラムからは数字で指定する必要があります。そのためPOIのプログラムをするときには、Excelのメニューの[ツール]-[オプション]で表示されるダイアログの[全般]-[R1C1参照形式を使用する]にチェックを入れておくと良いでしょう。この設定を行うと「A~IV」という表示が「1~256」という表示に変更されるため、アルファベットを数字に変換する手間が不要になります。複雑な帳票を作成するときには、この設定に変更しておくと便利でしょう。

列表示を数字にする設定
列表示を数字にする設定

まとめ

 この記事では、JavaからPOIを使用してExcelを出力させる方法を解説しました。Excel出力のポイントを簡単にまとめると次のようになります。

  1. ファイルの読込・・・POIFSFileSystemクラス
  2. ワークブックの読込・・・HSSFWorkbookクラス
  3. シートの読込・・・HSSFWorkbook#getSheetメソッド
  4. 行の読込・・・HSSFSheet#getRowメソッド
  5. セルの読込・・・HSSFRow#getCellメソッド
  6. セルのエンコードを設定・・・HSSFCell#setEncodingメソッド
  7. セルに文字列を設定・・・HSSFCell#setCellValueメソッド

 Excelに対するプログラムはサンプルと似たようなパターンがほとんどなので、この基本的な流れを押さえておくと良いでしょう。

参考資料

  1. Jakarta POI
  2. POIドキュメント翻訳
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 青木 淳夫 (株式会社ネクストスケープ)(アオキ アツオ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5