Teedaのサンプルアプリを読んでみる(6)

TodoListPageで残っているのは[Todo一覧のCSV出力]が押されたとき実行されるdoDownload()関連。最初にdownloadするデータを(一時)ファイルとして出力するのだが、その処理はDownloadLogic#getFile()で行っている。Churaの規約とかSMART deployを見ると、クラス名が"Logic"で終わっているので「アプリケーションの業務処理を行うインターフェース」ということになる。パッケージ名はルートパッケージ(=jp.co.gihyo.javaexpert.todo)+個別パッケージlogicではなく、TodoListPageと同じパッケージjp.co.gihyo.javaexpert.todo.web.todoに属している。つまりDownloadLogicはサブアプリケーションtodo固有のものとなる。TodoListPageには、このインタフェースを実装したクラスのインスタンスが(downloadLogicへ)自動的にDIされるけど、そのとき使われるsetterメソッドは自分で用意しておく必要がある。

	public void setDownloadLogic(final DownloadLogic downloadLogic) {
		this.downloadLogic = downloadLogic;
	}

Seasarやってる人にとっては当たり前だけど、Teedaから始める人は多分わからないかもね。さてそのDIされるサブアプリケーション固有のLogic実装クラスはどこに作るか?SMART deployにも、Java Expert#01を見ても書いてないような感じ。ただこのサンプルアプリの実装がjp.co.gihyo.javaexpert.todo.web.todo.impl.DownloadLogicImplなので「サブアプリケーション下にimplというパッケージを作り、そこへインタフェース名+"Impl"というクラス名で作成しておく」ということなんだろう。

ということでgetFile()の実装を見ると、TodoDao#selectAll()を実行して、結果を"javaexpert-sample.csv"というファイルとして出力している。実行するタイミングによっては、画面に表示されているものと違ったり、他の人の実行結果が上書きされたりしないか気になるところだけど、その辺はサンプルだからスルーしときましょう。で、このメソッド自体はFileをreturnして終わり。

doDownload()へ戻ると、HttpServletResponseに対しコンテントタイプをセットして、ファイル名もヘッダへセットする。この辺は通常のDownload処理と同じなんだけど、このHttpServletResponseオブジェクトもDIされたもの、というのがポイント。HttpServletResponseならresponseというプロパティを用意して、以下のようなsetterを作っておけばOK。

	public void setResponse(final HttpServletResponse response) {
		this.response = response;
	}

あとはHttpServletResponseからOutputStreamを取得して、そこへgetFile()が返したファイルの内容を出力する。最後に以下の処理を実行。

	this.facesContext.responseComplete();

facesContextも自動的にDIされたもので、FacesContextのこと。これはJSFの決まりごとらしく、このjavax.faces.context.FacesContext#responseComplete()を呼び出すとJSFレンダリングをしなくなる、ということらしい。まぁCSVのDownloadだからレンダリング不要だわな。

そのDownload中に例外が発生したら、以下のように例外AppFacesExceptionを投げているんだけど、これに関する説明が見つからないんだよね~。

	throw new AppFacesException("E0000002");

そういえば、これDownloadLogicImplにもあったね。多分引数に対応するメッセージはappMessages.propertiesとかappMessages_ja.propertiesに定義されているものだろう、と推測はできるけどね。要は処理中に致命的なエラーがあって、続行不能な場合とかはこんな感じで抜ければいいのね。