【Angular + Spring Boot】ファイルのダウンロードを実装する
バックエンド ( Spring Boot ) からPDFファイルをレスポンスとして返し、フロントエンド ( Angular ) へダウンロードするという動きを作っていきます。
Angular + Spring Boot でファイルのダウンロードを実装する
今回使用した環境
インターネット接続可能のオンラインの環境
64 ビット オペレーティング システム
Windows 10 22H2
Angular CLI: 13.3.10
Node: 16.15.0
Spring Boot: 3.0.0
Java: 17.0.3.1
ソース ( バックエンド )
バックエンド側では「test.pdf」をレスポンスとして返しています。
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import jakarta.servlet.http.HttpServletResponse;
@Controller
public class FileDownloadController {
@GetMapping(value ="download-test")
public void download(HttpServletResponse response) {
try (OutputStream outputStream = response.getOutputStream();) {
//ダウンロードファイルをバイト配列に変換
Path path = Paths.get("D:/work/test.pdf");
byte[] fileByte = Files.readAllBytes(path);
//レスポンスヘッダに値をセット
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=test.pdf");
response.setContentLength(fileByte.length);
outputStream.write(fileByte);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
上記コードはSpringBoot ファイルをダウンロードするサンプルのサイトを参考にさせていただきました。
ソース ( フロントエンド )
html側です。
ダウンロードボタンをクリックするとバックエンド側へリクエストを送信し、レスポンスのpdfファイルをaタグに埋め込んでそれをダウンロードする。
という流れです。このやり方が良いやり方なのかどうかはわかりませんが…。
<p>download-test works!</p>
<button (click)="download()">ダウンロード</button>
<div style="display: none;">
<a #downloadtag [href]="safeResourceUrl" target="_blank"
download="test.pdf">Download</a>
</div>
TypeScript側です。
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
@Component({
selector: 'app-download-test',
templateUrl: './download-test.component.html',
styleUrls: ['./download-test.component.css']
})
export class DownloadTestComponent implements OnInit {
safeResourceUrl: SafeResourceUrl;
@ViewChild('downloadtag') downloadtag: ElementRef;
constructor(
private http: HttpClient,
private sanitizer: DomSanitizer,
private changeDetectorRef: ChangeDetectorRef,
) { }
ngOnInit(): void {
}
download(): void {
this.http.get("http://localhost:8080/download-test",
{responseType: "blob"}).subscribe((blob) => {
this.safeResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl(
URL.createObjectURL(blob));
const downloadtag = <HTMLLinkElement>(this.downloadtag.nativeElement);
this.changeDetectorRef.detectChanges();
downloadtag.click();
})
}
}
25行目でバックエンドへのリクエストを行っています。
26行目の"blob"とはバイナリでレスポンスが返ってきたことを意味しています。
30行目は強制的に#downloadtagへsafeResourceUrlの値をバインディングしています。※これをしないとバインディング前にダウンロードが実行されてしまい、不正なファイルとなるケースがありました。
動作確認
ダウンロードボタンをクリックすることでtest.pdfがダウンロードできました。
※今回は CORS ( クロスオリジン ) の問題はブラウザ起動時のオプションで無効にしています。
以上となります。
ここまでお読みいただきありがとうございました。