2016-06-16 12 views
6

Domyślny interfejs MultiPartResolver w pakiecie rozruchowym obsługuje przesyłanie plików wieloczęściowych przez przechowywanie ich w lokalnym systemie plików. Przed wprowadzeniem metody kontrolera cały plik wieloczęściowy musi zakończyć przesyłanie do serwera.Spring - Jak przesyłać strumieniowo pliki wieloczęściowego pliku do bazy danych bez przechowywania w lokalnym systemie plików

Przechowujemy wszystkie nasze przesłane pliki bezpośrednio do bazy danych, a nasze serwery mają bardzo mały limit dyskowy, więc jeśli duży plik zostanie przesłany, widzimy numer IOExeption - Disk quota exceeded.

Czy istnieje sposób na uzyskanie strumienia bezpośrednio z przychodzącego żądania klienta, zanim Spring MultiPartResolver zapisze plik w lokalnym systemie plików, abyśmy mogli bezpośrednio przesyłać strumieniowo do naszej bazy danych?

+0

Co baza danych używasz? – Songo

+0

Używamy AWS S3 – McLovin

Odpowiedz

5

Można użyć apache bezpośrednio, jak opisano tutaj https://commons.apache.org/proper/commons-fileupload/streaming.html.

@Controller 
public class UploadController { 

    @RequestMapping("/upload") 
    public String upload(HttpServletRequest request) throws IOException, FileUploadException { 

     ServletFileUpload upload = new ServletFileUpload(); 

     FileItemIterator iterator = upload.getItemIterator(request); 
     while (iterator.hasNext()) { 
      FileItemStream item = iterator.next(); 

      if (!item.isFormField()) { 
       InputStream inputStream = item.openStream(); 
       //... 
      } 
     } 
    } 
} 

Upewnij się, że mechanizm sprężynowania jest odłączony.

application.yml:

spring: 
    http: 
     multipart: 
     enabled: false 
4

Właściwie to nie jest trywialne zadanie. Jeśli chcesz zapisać strumień z klienta bezpośrednio do bazy danych, musisz ręcznie przetworzyć żądanie. Istnieje kilka bibliotek, które mogą uprościć to zadanie. Jednym z nich jest "Apache Commons FileUpload". Poniżej bardzo prosty przykład, jak można przetwarzać przychodzące żądanie multipart/form-data przez tę bibliotekę.

@Controller 
public class Controller{ 

    @RequestMapping("/upload") 
    public String upload(HttpServletRequest request){ 

     String boundary = extractBoundary(request); 

     try { 
      MultipartStream multipartStream = new MultipartStream(request.getInputStream(), 
       boundary.getBytes(), 1024, null); 
      boolean nextPart = multipartStream.skipPreamble(); 
      while(nextPart) { 
       String header = multipartStream.readHeaders(); 

       if(header.contains("filename")){ 
        //if input is file 
        OutputStream output = createDbOutputStream(); 
        multipartStream.readBodyData(output); 
        output.flush(); 
        output.close(); 
       } else { 
        //if input is not file (text, checkbox etc) 
        ByteArrayOutputStream output = new ByteArrayOutputStream(); 
        multipartStream.readBodyData(output); 
        String value = output.toString("utf-8"); 
        //... do something with extracted value 
       } 
       nextPart = multipartStream.readBoundary(); 
      } 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     }  
    } 

    private String extractBoundary(HttpServletRequest request) { 
     String boundaryHeader = "boundary="; 
     int i = request.getContentType().indexOf(boundaryHeader)+ 
      boundaryHeader.length(); 
     return request.getContentType().substring(i); 
    }  
} 

Stół do woli pola plik wygląda następująco:

Content-Disposition: form-data; name="fieldName"; filename="fileName.jpg" 
Content-Type: image/jpeg 

Header dla prostego pole to wygląda:

Content-Disposition: form-data; name="fieldName"; 

nocie, że ten fragment jest po prostu uproszczony przykład, aby pokazać kierunek . Nie ma żadnych szczegółów, takich jak: wyodrębnianie nazwy pola z nagłówka, tworzenie wyjściowego strumienia bazy danych itp. Możesz zaimplementować wszystkie te rzeczy przez siebie. Przykłady nagłówków pól zapytania wieloczęściowego można znaleźć w RFC1867. Informacje o multipart/form-dataRFC2388.

+0

Mam to głównie działa z nagłówkiem '" Content-Type: multipart/form-data; boundary = ---- WebKitFormBoundary7MA4YWxkTrZu0gW "-F" filename = test "-F" file = @ myimage. jpg "' – McLovin

Powiązane problemy