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コードを一掃せよ!
←この記事が役に立ったという方はクリックお願いします。