12

Đang cố gắng tải lên tệp lớn bằng API tải lên tệp Apache Commons 'trực tuyến'.SpringBoot: Tải lên tệp tải lên lớn bằng cách sử dụng Apache Commons FileUpload

Lý do tôi đang sử dụng Trình tải lên tệp của Apache Commons chứ không phải trình tải lên Spring Multipart mặc định là nó không thành công khi chúng tôi tải lên kích thước tệp rất lớn (~ 2GB). Tôi làm việc trên một ứng dụng GIS, nơi các tệp tải lên như vậy khá phổ biến.

Mã đầy đủ cho bộ điều khiển tập tin tải lên của tôi là như sau:

@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; 
    } 

} 

Vấn đề là các getItemIterator(request) luôn trả về một iterator mà không có bất kỳ mục (ví dụ: iter.hasNext()) luôn trả về false.

tập tin application.properties của tôi là như sau:

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 

Quan điểm JSP cho /uploader là như sau:

<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> 

Những gì tôi có thể làm sai?

+4

Bạn đã tắt hỗ trợ đa luồng suối không, giải pháp của bạn sẽ không hoạt động và Spring đã phân tích cú pháp các yêu cầu. Thay thế tất cả các thuộc tính 'multipart' bằng một' multipart.enabled = false' duy nhất để vô hiệu hóa việc xử lý mặc định. –

+0

Tôi đã không thực hiện bất kỳ điều gì cụ thể để vô hiệu hóa hỗ trợ đa phần xuân. Tôi đã thử thêm 'multipart.enabled = false' vào tệp' application.properties' của tôi. Tuy nhiên, một khi tôi làm điều đó, tôi chỉ nhận được một '405: Yêu cầu phương pháp' POST 'không được hỗ trợ' lỗi mỗi khi tôi thực hiện một tải lên. – balajeerc

+0

Điều này sẽ cho biết ánh xạ sai hoặc đăng lên sai url ... Bật ghi nhật ký gỡ lỗi và xem URL bạn đang đăng và URL nào mà phương thức điều khiển của bạn được đối sánh. –

Trả lời

19

Nhờ một số nhận xét rất hữu ích của M.Deinum, tôi đã giải quyết được vấn đề. Tôi đã làm sạch một số bài đăng gốc của mình và đăng bài này dưới dạng câu trả lời hoàn chỉnh để tham khảo trong tương lai.

Sai lầm đầu tiên tôi đang thực hiện không vô hiệu hóa mặc định MultipartResolver mà Spring cung cấp. Điều này đã kết thúc trong xử lý giải quyết các HttpServeletRequest và do đó tiêu thụ nó trước khi bộ điều khiển của tôi có thể hành động trên nó.

Cách để vô hiệu hóa nó, nhờ M. Deinum là như sau:

multipart.enabled=false 

Tuy nhiên, vẫn còn một cái bẫy ẩn chờ đợi tôi sau này. Ngay khi tôi tắt trình phân giải nhiều phần mặc định, tôi bắt đầu nhận được lỗi sau khi cố gắng tải lên:

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

Trong cấu hình bảo mật của mình, tôi đã bật tính năng bảo vệ CSRF. Đó là đòi hỏi mà tôi gửi yêu cầu POST của tôi theo cách sau đây:

<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> 

Tôi cũng sửa đổi điều khiển của tôi một chút:

@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; 
    } 
} 

nơi đáp ứng chỉ là một loại phản ứng chung đơn giản tôi sử dụng:

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

Vui lòng thử thêm spring.http.multipart.enabled=false vào application.properties tệp.

3

Nếu bạn đang sử dụng phiên bản khởi động mùa xuân gần đây (Tôi đang sử dụng 2.0.0.M7) thì tên thuộc tính đã thay đổi. Mùa xuân bắt đầu sử dụng tên công nghệ cụ thể

spring.servlet.multipart.MaxFileSize = -1

spring.servlet.multipart.maxRequestSize = -1

spring.servlet.multipart.enabled = false

Nếu bạn nhận được ngoại lệ StreamClosed do triển khai nhiều hoạt động được , sau đó tùy chọn cuối cùng cho phép bạn vô hiệu hóa việc thực hiện mùa xuân mặc định

Các vấn đề liên quan