7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Struts2のファイルダウンロード処理で日本語名のファイルをダウンロードする

Last updated at Posted at 2014-04-21

Struts2で日本語ファイル名のファイルダウンロードがえっらいハマったのでメモです。

#streamのparamについて
単純にファイルをダウンロードするだけであれば、streamのパラメタを以下のようにすればダウンロードできます。

@Result(name = "success", type = "stream",
 params = { "inputName", "inputStream",
  "contentType", "application/octet-stream; charset=UTF-8",
  "contentLength", "${ contentLength }",
  "contentDisposition", "attachment; filename = ${fileName}"
 }
)

fileNameにファイル名を指定してやればいいのですが、2バイト文字が含まれるとブラウザ側で化けます。
これを回避するにはブラウザを判定して適切にファイル名をエンコードする必要がありますが、このfileNameだけでは足りませんので、パラメタを以下のようにします。

@Result(name = "success", type = "stream",
 params = { "inputName", "inputStream",
  "contentType", "application/octet-stream; charset=UTF-8",
  "contentLength", "${ contentLength }",
  "contentDisposition", "attachment; filename = ${fileName};filename*=utf-8''${encodedFileName}"
 }
)

この追加したencodedFileNameにもエンコードしたファイル名を指定しますが、こちらはブラウザに関係なくUTF8でエンコードしたものを指定します。
つまり、 ブラウザごとにエンコードしたファイル名とUTF8でエンコードしたファイル名 の2つが必要になります。
この例ではfileNameに指定するファイル名をブラウザごとにエンコードしてやる必要があります。

#サンプル
以下、ファイルダウンロードアクションのサンプルです。

@Result(name = "success", type = "stream", params = { "inputName",
        "inputStream", "contentType",
        "application/octet-stream; charset=UTF-8", "contentLength",
        "${ contentLength }", "contentDisposition",
        "attachment; filename = ${fileName};filename*=utf-8''${encodedFileName}" })
@Action(value = "download")
public class DownloadAction extends ActionSupport {

    /** ファイル名. */
    private String fileName;
    /** エンコードしたファイル名. */
    private String encodedFileName;
    /** ファイルサイズ. */
    private long contentLength;
    /** ストリーム. */
    private InputStream inputStream;

    // getter/setterのコードは省略

    @Override
    public final String execute() throws Exception {

        // ダウンロード対象ファイル
        String filePath = "日本語ファイル.txt";

        // 対象ファイル読み込み
        File exportFile = new File(filePath);

        // ストリームに読込
        this.inputStream = new BufferedInputStream(
                new FileInputStream(filePath));

        // ファイルサイズ取得
        this.contentLength = exportFile.length();

        // ブラウザで分岐
        String agent = ServletActionContext.getRequest()
                .getHeader("User-Agent");
        if (agent.indexOf("IE ") >= 0) {
            // IE
            this.fileName = URLEncoder.encode(exportFile.getName(), "UTF-8");
            this.encodedFileName = URLEncoder.encode(exportFile.getName(),
                    "UTF-8");
        } else {
            // IE以外
            this.fileName = exportFile.getName();
            this.encodedFileName = URLEncoder.encode(exportFile.getName(),
                    "UTF-8");
        }

        return "success";
    }

}

この例ではIEのみ分岐させてfileNameをエンコードしています。
とりあえずIE8~11、Firefox、Chromeで2バイト文字のファイルがダウンロードできることは確認しています。

#server.xml
これ書くの忘れてた・・・

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8" useBodyEncodingForURI="true"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8" useBodyEncodingForURI="true"/>

の様にエンコードを指定してやります。
特にEclipseの開発環境をそのまま使用しているとデフォルト値なので、これ設定しないとだめだったわ。

以上!

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?