SAStrutsでファイルダウンロード

追記


ひがさんから指摘されて実験してみたのですが、自分の勘違いだったのか拡張子なしでも特に問題なかったようです。訂正します。SAStrutsでは、ResponseUtil#download(String, byte[])を使えばダウンロード処理をカンタンに記述できるそうです。ひがさん、ありがとうございました。

というわけで以下の記述は見なくていいです

Webアプリで動的生成したファイルのダウンロード処理を行うと、Internet Explorerで問題になるケースが多い。例えばダウンロードダイアログで保存をした場合にリクエストを2回行うなど謎の動きをする。

IEダウンロード問題の最もスマートで簡単な解決方法は、リクエストURLの最後に拡張子を付けること。さすればIEの怪しい動作もなくなり、HTTP標準でないContent-dispositionのようなヘッダも不要になる。

Tomcatではjpg、csv、zip等の拡張子で終わるURLはデフォルトでは静的ファイルとして処理されてしまうが、それらのリクエストもサーブレットで処理するようにweb.xmlの設定を書き換えることができる。

さて、今回SAStrutsで開発しておりダウンロード処理が必要になった。SAStrutsRoutingFilterというものでアクションにディスパッチするのだが、ソースコードを見れば分かるようにパスにドットを含むリクエストをアクションにディスパッチしないようになっている。

SAStrutsのurlPatternを使って…、

/**
 * CSVファイルを生成してダウンロード
 */
@Excute(urlPattern = "download/{id}/{filename}")
public String download() {
   Hoge hoge = hogeService.findById(hogeForm.id)
   ...
}

として、/download/1/hoge.csvというURLでアクセスしてもこのアクションメソッドは呼び出されず、静的ファイルへのリクエストとして処理されて404 not found。困った。

しかしオープンソースなのだから改造すればいいだけのこと。RoutingFilterをコピペ継承wwwして1行変更、パスがdownloadという文字列を含んでいればアクションにディスパッチするオレRoutingFilterを作成してweb.xmlに設定。タダのサーブレットフィルタなのでSeasar自体をリビルドする必要もなく簡単です*1

ダウンロード処理でお困りのプログラマはぜひお試しあれ。

*1:サーブレットフィルタでなくてもSeasar自体が自身のDI機能を使ったコンポーネントの集合体のようなものなので、オレ機能追加にあたってリビルドが必要な場面というのは根本的に挙動を変更するような魔改造だけだろう