環境:
私は、zipアーカイブをダウンロードするために使用されるエンドポイントを持っています。
@GetMapping
public DeferredResult<StreamingResponseBody> download(/**params**/) {
}
ファイルおよびファイルサイズの数に起因して、メモリにそれらのすべてを維持することはできません(つまり私は、外部サービスからファイルのチャンクを読んで一時ディレクトリにそれらを保存し、zipアーカイブを作成するにチャンクで書き込みファイルする必要があります-郵便番号は、アーカイブが行われた後、すべての一時ファイルを削除し、この時点で私は、ディスク上のアーカイブが残っています)、その後、クライアントにジップバックをストリーミングします- 。
私は、機能を実装するために管理してきましたが、私は、要求(サービスは、複数のクライアントで使用されていることに注意してください - ので、複数のダウンロードが同時に起こることができるはずです)の後にクリーンアップするための最良の方法であることを確認していません。
現在、私は使用していますHandlerInterceptor
、アーカイブのためのランダムな名前を生成するpreHandle
方法と要求属性としてそれを一緒に渡します。要求属性はアーカイブを生成し、アーカイブ名として使用されているサービスに渡されます。その後、中afterCompletion
インターセプタの方法、私がリクエスト属性からアーカイブ名を読み、アーカイブを削除します。
class ZipInterceptor implements HandlerInterceptor {
public static final String ZIP_ATTRIBUTE_NAME = "zipName";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(isApplicable(request)){
request.setAttribute(ZIP_ATTRIBUTE_NAME, generateZipName());
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if(isApplicable(request)){
deleteZip((String)request.getAttribute(ZIP_ATTRIBUTE_NAME));
}
}
}
もう一つは、私が考えられてきたことをアプローチ:
- クライアントにアーカイブ名を返す(ヘッダとして、あるいはダウンロードされたファイルの名前など)およびアーカイブを削除するには、新しいエンドポイントを呼び出すために、クライアントに依存します。主な欠点は、私は、このプロトコルを使用してにクライアントを強制する方法はありません(とフルディスクで終わるかもしれない)ということです。
- ジョブに毎時間(または他の時間間隔)とクリーンな古いアーカイブを実行します。欠点は、私は確か天候のために知っていないファイルは、(任意の時間間隔がまだストリーミング終了していないファイルを削除しますので、十分に大きいファイルの場合)クライアントに戻ってかないストリーミング終了したことです。
あなたの意見は、このシナリオを処理するための最良の方法では、どちらでしょうか?
JB Nizetはコメントで指摘したように、最善のアプローチはするだろうすべてのディスク上のファイルを保存していません。
リクエストがクライアントに返された後、特定のコンテキストは、ディスク上のファイルをあなたに残されている場合は、それらを取り除くために次のアプローチを使用することができます。
class CleanupInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// do cleanup here
}
}
誰もがこれを取り組むために、よりエレガントな解決策を見つけた場合、ここにあなたの答えを投稿してください。