Spring Bootで、imgタグ等からリクエストされたイメージ表示要求に対して、イメージをレスポンスするためのコードスニペットは以下。
@Value("${application.iamge-max-age}")
private String imageMaxAge;
@GetMapping(value = "/view/{fileId}")
public void view(HttpServletResponse response, @PathVariable String fileId) throws IOException {
// ファイルIDに対応するイメージファイルパスを取得する処理はアプリケーション依存
String path = foobar.findById(fileId);
if (file != null) {
// ブラウザにキャッシュさせる。86400秒=1日
response.setHeader("Cache-Control", "max-age=" + imageMaxAge);
// MimeType算出/設定
FileTypeMap filetypeMap = FileTypeMap.getDefaultFileTypeMap();
String mimeType = filetypeMap.getContentType(path);
response.setContentType(mimeType);
try (InputStream is = new FileInputStream(path);
BufferedInputStream bis = new BufferedInputStream(is);
OutputStream os = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os)) {
// バッファリングすることでどの程度パフォーマンスがあがるのか?
final long transferSize = bis.transferTo(bos);
log.info("Response complete.fileId={},mimeType={},size={}byte", fileId, mimeType, transferSize) ;
} catch (FileNotFoundException ex) {
// DBレコード上にイメージファイルが存在することになっているのに、存在しない、
// ということはなんらかのデータ不整合が発生しているため、500:Internal Server Errorとする。
log.error("File not found. filePath={}", file.getPath());
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} catch (IOException ex) {
log.error("Faild read file. Cause by file not exists on this server. filePath={}" + path, ex);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
} else {
// 指定されたファイルIDがDBレコード上に存在しない理由は、
// 1.クライアントから不正なリクエストを要求されている
// 2.イメージファイルの表示を要求するきっかけとなるそもそものサーバレスポンスが間違っている
// のどちらか。2の場合はなんらかのバグだが、ここではどちらの理由であるかが判定できないため、
// クライアント側には404エラーで応答する。
log.warn("File not found. Cause by invalid file id. fileId={}", fileId);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}