12

'Streaming' Apache Commons File Upload APIを使用して大きなファイルをアップロードしようとしています。SpringBoot:Apache Commonsを使用した大規模なストリーミングファイルアップロードFileUpload

デフォルトのSpring MultipartアップローダではなくApache Commons File Uploaderを使用しているのは、非常に大きなファイルサイズ(〜2GB)をアップロードすると失敗するからです。このようなファイルのアップロードが一般的なGISアプリケーションに取り組んでいます。次のように

私のファイルアップロードコントローラの完全なコードは次のとおりです。

@Controller 
public class FileUploadController { 

    @RequestMapping(value="/upload", method=RequestMethod.POST) 
    public void upload(HttpServletRequest request) { 
     boolean isMultipart = ServletFileUpload.isMultipartContent(request); 
     if (!isMultipart) { 
      // Inform user about invalid request 
      return; 
     } 

     //String filename = request.getParameter("name"); 

     // Create a new file upload handler 
     ServletFileUpload upload = new ServletFileUpload(); 

     // Parse the request 
     try { 
      FileItemIterator iter = upload.getItemIterator(request); 
      while (iter.hasNext()) { 
       FileItemStream item = iter.next(); 
       String name = item.getFieldName(); 
       InputStream stream = item.openStream(); 
       if (item.isFormField()) { 
        System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected."); 
       } else { 
        System.out.println("File field " + name + " with file name " + item.getName() + " detected."); 
        // Process the input stream 
        OutputStream out = new FileOutputStream("incoming.gz"); 
        IOUtils.copy(stream, out); 
        stream.close(); 
        out.close(); 

       } 
      } 
     }catch (FileUploadException e){ 
      e.printStackTrace(); 
     }catch (IOException e){ 
      e.printStackTrace(); 
     } 
    } 

    @RequestMapping(value = "/uploader", method = RequestMethod.GET) 
    public ModelAndView uploaderPage() { 
     ModelAndView model = new ModelAndView(); 
     model.setViewName("uploader"); 
     return model; 
    } 

} 

トラブルがgetItemIterator(request)は、常にすべてのアイテムを持っていないイテレータを返すことである(すなわちiter.hasNext())常にfalseを返します。私は間違って何をしているのかもしれない

<html> 
<body> 
<form method="POST" enctype="multipart/form-data" action="/upload"> 
    File to upload: <input type="file" name="file"><br /> 
    Name: <input type="text" name="name"><br /> <br /> 
    Press here to upload the file!<input type="submit" value="Upload"> 
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> 
</form> 
</body> 
</html> 

次のように/uploaderため

spring.datasource.driverClassName=org.postgresql.Driver 
spring.datasource.url=jdbc:postgresql://localhost:19095/authdb 
spring.datasource.username=georbis 
spring.datasource.password=asdf123 

logging.level.org.springframework.web=DEBUG 

spring.jpa.hibernate.ddl-auto=update 

multipart.maxFileSize: 128000MB 
multipart.maxRequestSize: 128000MB 

server.port=19091 

JSP図であり、以下のよう

マイapplication.propertiesファイルがありますか?

+4

あなたのソリューションは動作しません。また、Springはすでにリクエストを解析しています。すべての 'multipart'プロパティを単一の' multipart.enabled = false'に置き換え、デフォルトの処理を無効にします。 –

+0

私はspring multipartサポートを無効にするために何もしていませんでした。私は 'application.properties'ファイルに' multipart.enabled = false'を追加しようとしました。しかし、これを行うと、アップロードを行うたびに '405:リクエストメソッド 'POST'がサポートされていないというエラーが出ます。 – balajeerc

+0

マッピングが間違っているか、間違ったURLに投稿された可能性があります...デバッグロギングを有効にして、あなたが投稿しているURLとコントローラメソッドが一致するURLを確認してください。 –

答えて

19

M.Deinumの非常に有益なコメントのおかげで、私は問題を解決することができました。私は私の元の投稿のいくつかを整理し、将来の参考のためにこれを完全な回答として掲示しています。

私が最初に間違えていたのは、Springが提供するデフォルトのMultipartResolverを無効にしていないことではありませんでした。これは、HttpServeletRequestを処理しているリゾルバで終わってしまい、コントローラを動作させる前に消費してしまいました。

次のように、M. Deinumのおかげで、それを無効にする方法だった:

multipart.enabled=false 

しかし、この後に私を待って別の隠された落とし穴は、まだありました。できるだけ早く私無効デフォルトのマルチパートリゾルバとして、私がアップロード作るしようとすると、次のエラーを取得開始しました:私のセキュリティ設定では

Fri Sep 25 20:23:47 IST 2015 
There was an unexpected error (type=Method Not Allowed, status=405). 
Request method 'POST' not supported 

を、私はCSRF保護を有効にしていました。それは私が次のように私のPOSTリクエストを送信することを余儀なく:

<html> 
<body> 
<form method="POST" enctype="multipart/form-data" action="/upload?${_csrf.parameterName}=${_csrf.token}"> 
    <input type="file" name="file"><br> 
    <input type="submit" value="Upload"> 
</form> 
</body> 
</html> 

また、私は少し私のコントローラを修正:

応答は、私が使用して単純なジェネリック応答型である
@Controller 
public class FileUploadController { 
    @RequestMapping(value="/upload", method=RequestMethod.POST) 
    public @ResponseBody Response<String> upload(HttpServletRequest request) { 
     try { 
      boolean isMultipart = ServletFileUpload.isMultipartContent(request); 
      if (!isMultipart) { 
       // Inform user about invalid request 
       Response<String> responseObject = new Response<String>(false, "Not a multipart request.", ""); 
       return responseObject; 
      } 

      // Create a new file upload handler 
      ServletFileUpload upload = new ServletFileUpload(); 

      // Parse the request 
      FileItemIterator iter = upload.getItemIterator(request); 
      while (iter.hasNext()) { 
       FileItemStream item = iter.next(); 
       String name = item.getFieldName(); 
       InputStream stream = item.openStream(); 
       if (!item.isFormField()) { 
        String filename = item.getName(); 
        // Process the input stream 
        OutputStream out = new FileOutputStream(filename); 
        IOUtils.copy(stream, out); 
        stream.close(); 
        out.close(); 
       } 
      } 
     } catch (FileUploadException e) { 
      return new Response<String>(false, "File upload error", e.toString()); 
     } catch (IOException e) { 
      return new Response<String>(false, "Internal server IO error", e.toString()); 
     } 

     return new Response<String>(true, "Success", ""); 
    } 

    @RequestMapping(value = "/uploader", method = RequestMethod.GET) 
    public ModelAndView uploaderPage() { 
     ModelAndView model = new ModelAndView(); 
     model.setViewName("uploader"); 
     return model; 
    } 
} 

public class Response<T> { 
    /** Boolean indicating if request succeeded **/ 
    private boolean status; 

    /** Message indicating error if any **/ 
    private String message; 

    /** Additional data that is part of this response **/ 
    private T data; 

    public Response(boolean status, String message, T data) { 
     this.status = status; 
     this.message = message; 
     this.data = data; 
    } 

    // Setters and getters 
    ... 
} 
1

spring.http.multipart.enabled=falseapplication.propertiesに追加してください。

3

最近のバージョンのスプリングブート(2.0.0.M7を使用しています)を使用している場合は、プロパティ名が変更されています。 技術固有の名前を使用して開始された春

spring.servlet.multipartmaxFileSizeの= -1

spring.servlet.multipart.maxRequestSize = -1

spring.servlet.multipart.enabled = falseを

あなたがアクティブである複数の実装によって引き起こさStreamClosed例外を取得している場合最後のオプションは、デフォルトのスプリング実装を無効にすることを可能にします。

関連する問題