環境
・Wildfly 10.0.0.Final
・Struts 2.3.29
・Struts Convention Plugin 2.3.29
・Struts2 CDI Plugin 2.3.29
struts.xml での struts.enable.DynamicMethodInvocation は true
現象
Apache POIで生成したxlsをStruts2でダウンロードすると日本語ファイルが文字化け…
csvのダウンロードはうまくいってるので
POIが良くないのか、それとも
レスポンスヘッダに設定している
contentType:application/msexcel; charset=utf-8
あたりか…!?ということで試行錯誤開始。
処理概要
@Result(name = "download", type = "stream", params = {
"inputName", "inputStream",
"contentType", "application/msexcel; charset=${ charset }",
"contentLength", "${ contentLength }",
"contentDisposition", "attachment; filename = ${ filename };filename*=utf-8''${ encodedFilename }"
})
public class ExcelDownload extends ActionSupport {
// 中略
public void download() {
org.apache.poi.ss.usermodel.Workbook wb = ワークブック生成処理();
byte[] byteArray = null;
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
wb.write(out);
byteArray = out.toByteArray(); // wb⇒outへ書き出しbyteArrayを得る.
} catch (IOException e) {
// エラーハンドリング処理.
}
if (ServletActionContext.getRequest().getHeader("User-Agent").indexOf("IE ") >= 0) {
// IEならfilenameもエンコードする.
this.filename = URLEncoder.encode(filename, "UTF-8");
} else {
// Non IE.
this.filename = filename;
}
this.encodedFilename = URLEncoder.encode(filename, "UTF-8");
// 中略
return "download";
}
}
よくあるこんな感じのソースで、調べてて一番有力なのが下記です。
CSVだとこれでうまくいってました。
Struts2のファイルダウンロード処理で日本語名のファイルをダウンロードする - Qiita
fileNameとencodedFileNameに対して
ブラウザによって(IEかどうか)値を変えてセットするやり方がメジャーなのかと思います。
また、調べて出てくるサイトの中では
Struts2でPoiを使ったダウンロード - QA@IT
が一番役立ちますが、これでは日本語ファイル名ダメでした。
ファイル名をISO-8859-1でエンコード
一律
this.filename = new String(filename.getBytes("MS932"), "ISO-8859-1");
で解消しました。
ExcelはISO-8859-1じゃないとダメらしいです。
IE分岐については自分らの環境では大丈夫でしたが一応テストした方が良さそうです。