諸元
処理の結果をファイルとして返すけど、ユーザーの任意のタインミングでダウンロードさせたい。
そうするとバックエンドでファイルを作り込んでおいて永続化(S3とか)するか、セッションにバイト配列として保持しておくか、または取得リクエストの際に別途作るのか・・・・・・。
いろいろやり方はあると思うのですが、データだけフロントに返しておいてフロント側で構築すればいいのでは?と思いました。
もちろん、ファイルの容量が大きくなってしまうような場合は取れない手段だと思うのですが。
また、ファイルの文字コードにはShift_JISとUTF8の2種類を出しわけられるようにするとします。
実現方法
バックエンド
適切な文字コードで表現したCSV内容をバイト配列化、Base64エンコードした文字列として返却します。
Springでの例です。
model.addAttribute("bytes", Base64.getEncoder().encodeToString(file.toByteArray()))
適当に埋め込んでおきます。
<input type="hidden" id="data" value="${bytes}" />
フロントエンド
// Base64からバイト配列に復元する
const bs = atob($('#data').val());
const bytes = new Uint8Array(bs.length);
for (let i = 0; i < bs.length; i++) {
bytes[i] = bs.charCodeAt(i);
}
// Fileオブジェクトを作る
// 第一引数がデータ
const file = new File([bytes.buffer], 'hoge.csv', {type: 'text/csv'});
// ダウンロード用a要素を作って
const a = document.createElement('a');
a.download = 'hoge.csv';
// fileを対象としたURLを作る
a.href = URL.createObjectURL(file);
document.body.append(a);
a.click();
単に持ってる文字列をファイル化したいなら第一引数は['hoge']
みたいな感じでいいんですが……。