環境
- Spring Boot v1.3.0
- java 8
- jquery
動機
画面遷移をせずダウンロードしたいが、HttpResponseHeaderクラスを使うのはなんだか気が引けたため、Springパッケージのクラスのみを使って実装。クライアント側の実装も忘れそうなため備忘。
実装
Controller
@RequestMapping("/download")
@ResponseBody
public ResponseEntity<byte[]> download() {
byte[] data = xxx; // xxx:byte[]形式のオブジェクト
// ResponseHeader
HttpHeaders header = new HttpHeaders();
header.add("Content-Type", "yyy"); // yyy:任意のContent-Type
header.add("Content-Disposition", "attachment; filename*=utf-8''" + URLEncoder.encode("zzz", "UTF-8")); // zzz:任意のファイル名
header.add("Set-Cookie", "fileDownload=true; path=/");
return new ResponseEntity<byte[]>(data, header, HttpStatus.OK);
}
- Content-Dispositionで強制的にダウンロード、かつ日本語ファイル名に対応。
- Set-Cookieしてるのはこの後クライアント側で使うため。
javascript
// formのサブミット時にイベント追加
$("#myform").submit(function() {
startLoading(); // ぐるぐる出す的メソッド
const COOKIE_KEY_FILEDOWNLOAD = 'fileDownload=';
var isFileDownload = false;
// ダウンロード完了まで繰り返す
var intervalId = setInterval(function() {
// cookieから fileDownload の取得
const COOKIES = document.cookie;
var position = COOKIES.indexOf(COOKIE_KEY_FILEDOWNLOAD);
if (position >= 0) {
var startIdx = position + COOKIE_KEY_FILEDOWNLOAD.length;
var endIdx = COOKIES.indexOf(';', startIdx);
if (endIdx < 0) {
endIdx = COOKIES.length;
}
isFileDownload = decodeURIComponent(COOKIES.substring(startIdx, endIdx)) == 'true';
}
// fileDownloadがtrueなら繰り返し終了
if (isFileDownload) {
clearInterval(intervalId);
var date = new Date();
date.setTime(date.getTime() - 1);
document.cookie = COOKIE_KEY_FILEDOWNLOAD + 'false; path=/; max-age=0';
stopLoading(); // ぐるぐるやめる的メソッド
}
}, 500);
});
- Set-Cookieされた値を参照することでダウンロード成功時にぐるぐるを止めるようにしている。
参考
- 日本語ファイル名ダウンロード https://www.greptips.com/posts/869/
- ResponseEntityの使い方 https://qiita.com/YAKINIKU/items/abaa54ba531a30850d10
- ファイルダウンロード完了後に画面遷移などをjavascriptで行う http://nabehiro.hatenablog.com/entry/20140208/1391850498
- javascriptでcookie https://so-zou.jp/web-app/tech/programming/javascript/cookie/