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"); |
以上で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; } |
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コードを一掃せよ!
←この記事が役に立ったという方はクリックお願いします。
| 固定リンク
| トラックバック (0)