1. ホーム
  2. tomcat

[解決済み] サーブレットアプリケーションでアップロードされたファイルを保存するための推奨方法

2022-08-16 21:21:50

質問

私は ここで を読むと、ポータブルではなく、トランザクションであり、外部パラメータを必要とするため、とにかくサーバーにファイルを保存すべきではないとのことです。しかし、tomcat (7) 用の tmp ソリューションが必要であり、サーバー マシンを (比較的) 制御できることを考えると、私はそれを知りたいと思います。

  • ファイルを保存するのに最適な場所は何ですか? 保存先は /WEB-INF/uploads (に保存すべきでしょうか? に保存する必要があります。 の下のどこか)または $CATALINA_BASE (の下のどこか(参照 ここで ) または ... ? JavaEE 6のチュートリアル はユーザーからパスを取得します (:wtf:) となります。注意 : このファイルは、いかなる方法でもダウンロード可能であってはなりません。

  • 詳細のようにコンフィグパラメータを設定する必要があります ここで ? 私はいくつかのコードを感謝します(私はむしろ相対パスを与えたい - ので、それは少なくともTomcatの移植性があります) - 。 Part.write() は有望に見えます - しかし、どうやら絶対パスが必要です

  • 私は、このアプローチの欠点とデータベース/JCR リポジトリの欠点との説明に興味があります。

残念ながら ファイルサーブレット はファイルのダウンロードに特化しているのに対し、@BalusC の アンサー はファイルのアップロードに集中しており、ファイルをどこに保存するかという部分は省略しています。

DBまたはJCRの実装(たとえば ジャックラビット のような) ソリューションが望ましいでしょう。

どのように解決するのですか?

アクセスしやすい場所に保管する を除く への回答で述べた理由から、IDE のプロジェクトフォルダ、またはサーバのデプロイフォルダを除いた、アクセス可能な場所に保管してください。 アップロードされた画像は、ページをリフレッシュした後にのみ利用可能です。 :

  1. IDE のプロジェクト フォルダーの変更は、サーバーのワーク フォルダーにすぐには反映されません。IDE には、サーバーの作業フォルダーが最新の更新と同期されるようにするバックグラウンド ジョブがあります (IDE 用語では "publishing" と呼ばれます)。これは、あなたが見ている問題の主な原因です。

  2. 現実のコードでは、アップロードされたファイルを Web アプリのデプロイ フォルダに格納することがまったく機能しない状況があります。一部のサーバーは (デフォルトまたは設定により) 配置された WAR ファイルをローカル ディスク ファイル システムに展開せず、代わりに完全にメモリ内に展開します。基本的に、デプロイされた WAR ファイルを編集して再デプロイしない限り、メモリ内に新しいファイルを作成することはできません。

  3. サーバーがデプロイされた WAR ファイルをローカル ディスク ファイル システムに展開する場合でも、単にそれらの新しいファイルが元の WAR ファイルの一部でないため、再デプロイまたは単純な再起動で、すべての新しく作成されたファイルは失われます。

ローカル ディスクのファイル システムのどこに保存されるかは、私にとっても他の人にとっても重要ではありません。 を実行します。 ではなく を使用してください。 getRealPath() メソッド . そのメソッドを使うのは 任意の の場合、憂慮すべきものです。

保存場所へのパスは、順番に多くの方法で定義することができます。あなたはそれをすべて 自分 . おそらく、ここがあなたの混乱の原因です。なぜなら、あなたは、サーバーが自動的にすべてを行うことを期待していたからです。以下のことに注意してください。 @MultipartConfig(location) ではなく は最終的なアップロード先を指定しますが、ケースファイルのサイズがメモリ保存の閾値を超えた場合の一時保存先を指定します。

そのため、最終的な保存先へのパスは、以下のいずれかの方法で定義することができます。

  • ハードコードする。

      File uploads = new File("/path/to/uploads");
    
    
  • 環境変数経由 SET UPLOAD_LOCATION=/path/to/uploads :

      File uploads = new File(System.getenv("UPLOAD_LOCATION"));
    
    
  • サーバ起動時のVM引数 -Dupload.location="/path/to/uploads" :

      File uploads = new File(System.getProperty("upload.location"));
    
    
  • *.properties というファイルエントリ upload.location=/path/to/uploads :

      File uploads = new File(properties.getProperty("upload.location"));
    
    
  • web.xml <context-param> 名前付き upload.location という名前と、値 /path/to/uploads :

      File uploads = new File(getServletContext().getInitParameter("upload.location"));
    
    
  • もしあれば、サーバーが提供するロケーションを使用します、例えば JBoss AS/WildFly :

      File uploads = new File(System.getProperty("jboss.server.data.dir"), "uploads");
    
    

いずれにせよ、以下のように簡単に参照・保存することができます。

File file = new File(uploads, "somefilename.ext");

try (InputStream input = part.getInputStream()) {
    Files.copy(input, file.toPath());
}

あるいは、ユーザーが偶然にも同じ名前の既存のファイルを上書きするのを防ぐために、ユニークなファイル名を自動生成したい場合。

File file = File.createTempFile("somefilename-", ".ext", uploads);

try (InputStream input = part.getInputStream()) {
    Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}

取得方法 part をJSP/Servletで取得する方法は JSP/Servletを使用してサーバーにファイルをアップロードするにはどうすればよいですか? を取得する方法と part をJSFで取得する方法は JSF 2.2 <h:inputFile> を使用してファイルをアップロードする方法は?保存されたファイルはどこにありますか?

注意 ではなく 使用 Part#write() で定義された一時的な保存場所からの相対パスを解釈するためです。 @MultipartConfig(location) . また、PDFファイルや画像ファイルなどのバイナリファイルを読み書きの際に、誤って Reader / Writer の代わりに InputStream / OutputStream .

こちらもご覧ください。