« Java:MySQLに金額を格納する | トップページ | Java:CSVパーサを作る(その1) - 簡易パーサ »

WebObjects:CSVレスポンスの実装

Webアプリケーションにおいて,データベースの内容をCSVデータにしてユーザにダウンロードさせたい場合があるかと思います。ここではWebObjectsの環境で作成するWebアプリでの実装例として,ボタンクリックに対するWebブラウザへのレスポンスをCSVデータとすることで,WebブラウザでCSVデータをダウンロードさせる実装例を示します。

【処理の概要】
WebObjectsのアクションメソッドの戻り値としてコンポーネントクラスのインスタンスを返すと,WebObjectsがそのクラスのappendToResponseメソッドを呼び出してWebブラウザへのレスポンスを作成します。この仕組みを使ってCSVデータを返すために,CSVデータを返すためのコンポーネントクラスを作り,メンバ変数にCSVデータセットしてappendToResponseメソッドが呼ばれればCSVレスポンスが作られるようにします。

【実装手順】
1)コンポーネントの作成
CSVデータを返すコンポーネントを作成します。
これは通常のHTMLを返すコンポーネントの新規作成と同じで,開発環境Xcodeの「新規ファイル」ダイアログから「WebObjects」→「Component」を選んで「次へ」ボタンで進み,ターゲットを「Application Server」にしてファイル名にコンポーネント名を入力して完了ボタンで作成を実行します。
ここでは仮に,コンポーネント名を「CSVExport」と指定することにします。

2)CSVデータを保持するメンバ変数と初期化メソッドの作成
CSVExport.javaにて,CSVデータとファイル名を保持するメンバ変数と,これに値を設定する初期化メソッドを実装します。

private String mFileName;
private String mCSVData;

public void init (
  String fileName,
  String csvData)
{
  mFileName = fileName;
  mCSVData = csvData;
}

3)appendToResponseのオーバーライド
CSVExport.javaにて「appendToResponse」メソッドを定義すると,Application.javaやSession.javaで定義したappendToResponseメソッドがオーバーライドされます。CSVデータを返す場合のappendToResponseメソッドは以下のようになります。このメソッドでは,出力するCSVファイルをExcelで開くことができるように,文字コードを「Windows-31J/MS932」に指定しています。
public void appendToResponse (
  WOResponse res,
  WOContext cont)
{
  res.setContextEncoding("MS932");
  super.appendToResponse(res, cont);
  if (mFileName != null && mCSVData != null) {
    res.setHeader("public", "Cache-Control");
    res.setHeader("public", "Pragma");
    res.setHeader("text/csv;charset=Windows-31J", "Content-Type");
    res.setHeader("attachment;filename=\""+mFileName+".csv\"", "Content-Disposition");
    res.setHeader(new Long(mCSVData.length()).toString(), "Content-Length");
    res.setContent(mCSVData);
    res.setStatus(res.HTTP_STATUS_OK);
  }
}

上記コードのうち,
res.setHeader("public", "Cache-Control");
res.setHeader("public", "Pragma");
IEのダウンロード問題に対処したものです。
以上でCSVExportコンポーネントの実装は完了です。

4)アクションメソッドからの呼び出し
Webアプリ上でボタンを押すと,CSVExportコンポーネントによりCSVファイルがダウンロードされるようにします。
WebアプリのCSVダウンロードボタンを配置したページのコンポーネントクラスにおいて,ボタンを押したときに呼ばれるアクションメソッドを用意して,その戻り値としてCSVExportクラスインスタンスを返すようにします。アクションメソッドは以下のようになります。
public CSVExport exportAction ()
{
  CSVExport nextPage = null;
  String fileName = buildFileName(); // ファイル名生成.
  String csvData = buildCSVData();  // CSVデータ生成.
  if (csvData != null && 0 < csvData.length()) {
    nextPage = (CSVExport)pageWithName("CSVExport");
    nextPage.init(fileName, csvData);
  }
  return nextPage;
}
このアクションメソッドをWebページのWOSubmitButtonなどにバインドすることにより,ユーザのボタン押下でCSVデータをWebブラウザからダウンロードすることができます。

5)CSVデータ生成メソッドの実装の概要
CSVデータの作成についてはJavaの「StringBuffer」クラスで組み立てるのが一般的かと思います。
CSVのデータフォーマットの仕様についてはRFC4180日本語訳)を参照してください。
この実装方法で巨大なCSVファイルを扱う場合,最後にtoStringメソッドでStringインスタンスを生成するときに,文字列データに必要なメモリサイズが倍になってしまうので,メモリ不足に注意しましょう。WebObjectsのメモリ不足対策はこちら
private String buildCSVData ()
{
  StringBuffer buff = new StringBuffer();
  buff.append("カラム1-1");
  buff.append(",");    // カンマ挿入.
  buff.append("\"");    // ダブルクォーテーション(二重引用符)挿入.
  buff.append("カラム1-2");
  buff.append("\"");
  buff.append("\r\n");   // 改行(CRLF)挿入.
  buff.append("カラム2-1");
  buff.append(",");
  buff.append("\"");
  buff.append("カラム2-2");
  buff.append("\"");
  buff.append("\r\n");

  return buff.toString();
}

※CSVの「数値/数値」をExcelで日付にしないために
ここで実装したしたCSVレスポンスのデータをユーザがダウンロードしてExcelで開いて閲覧・編集する場合,フィールドデータの形式が「数値/数値」または「数値-数値」で,数値が日付として解釈できる範囲内の場合,Excelはこれを勝手に日付データとして取り込んでしまいます。
これに対する対処法として,CSVレスポンスデータを組み立てるときにフィールドデータの先頭に半角スペースを入れる,というのが最も手っ取り早い対処法かと思います。先頭に半角スペースを入れた「 数値/数値」のデータをExcelに読み込ませると,Excelはこのデータの先頭の半角スペースを削除して日付ではなく文字列としてデータを取り込みます。
参考:Excel で文字列または数値が意図しない表示形式に変換される(Microsoftサポートオンライン)

※上記コードでは,整形のため全角スペースを使用している部分があります。
【著作権表記】上記コードを含む本ブログのプログラムコードは,私的利用可,商用利用可,改変しての利用可です。利用の際に作者に許諾を得る必要はありません。

■関連情報
CSVの仕様:RFC4180日本語訳
Java:Shift_JISのエイリアスの変更について
Microsoftサポートオンライン:IEのダウンロードの問題
Java:CSVパーサを作る[その1][その2][その3]
WebObjects:[API Reference(javadoc)][ADC Tools][サポート]

■関連書籍をAmazonで検索:[WebObjects 和書 洋書]
コーディングの掟 現場でよく見る不可解なJavaコードを一掃せよ!

にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。

|

« Java:MySQLに金額を格納する | トップページ | Java:CSVパーサを作る(その1) - 簡易パーサ »

WebObjects」カテゴリの記事

プログラミング」カテゴリの記事

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/505963/40519083

この記事へのトラックバック一覧です: WebObjects:CSVレスポンスの実装:

« Java:MySQLに金額を格納する | トップページ | Java:CSVパーサを作る(その1) - 簡易パーサ »