9

Hier ist was ich mache. Ich möchte mehrteilige Dateien über Ajax in meine Spring Web App hochladen. Wenn der Server die POST-Anforderung empfängt, erstellt er eine Ticketnummer in der Datenbank. Es startet dann einen Thread, der den eigentlichen Dateiupload behandelt. Der Server gibt dann die Ticketnummer zurück.Asynchroner Datei-Upload im Frühjahr

Ich verwende den CommonsMultipartResolver, um die Anfrage zu bearbeiten, und ich habe das ResolveLazily-Flag auf True festgelegt, damit das Multipart nicht sofort aufgelöst wird.

hier ist also etwas entlang der Linien von dem, was ich habe

@Controller 
public class myController{ 

    @RequestMapping(value = "/upload", method = RequestMethod.POST) 
    @ResponseStatus(value = HttpStatus.OK) 
    @ResponseBody 
    public String upload(MultipartHttpServletRequest request, String fileName){ 

     String ticket = dao.createUploadTicket(fileName); 
     Runnable run = new Runnable(){ 

      @Override 
      public void run(){ 

       dao.writeUpdate(ticket, "Getting data from request"); 
       final MultipartFile file = request.getFile("theFile"); 
       dao.writeUpdate(ticket, "Multipart file processed"); 
       try { 
        dao.writeUpdate(ticket, "Saving file to disk"); 
        file.transferTo(new File("/myDirectory")); 
        dao.writeUpdate(ticket, "File saved to disk"); 
       } 
       catch(Exception e){ 
        dao.writeUpdate(ticket, "File upload failed with the exception " + e.toString()); 
       } 
      } 
     }; 
     Thread t = new Thread(run); 
     t.start(); 
     return ticket; 
    } 
} 

Also hier der Punkt ist, dass die Ticket-Nummer verwendet werden kann, um die Fortschritte Updates zu erhalten. Angenommen, eine große Datei wird hochgeladen. Der Client, der den POST der Datei hochgeladen hat (in diesem Fall eine Ajax-Anfrage), kann dies asynchron tun und eine Ticketnummer zurückerhalten. Der Kunde kann diese Ticketnummer verwenden, um die Phase des Datei-Uploads zu bestimmen und Informationen auf einer anderen Seite anzuzeigen.

Eine andere Verwendung ist, dass ich eine HTML-Seite haben kann, die eine Anfrage an den Server für alle ticket-Nummern, dann zeigt eine Live-Ansicht aller Dateiuploads, die auf dem Server stattfinden.

Ich konnte dies nicht zum Funktionieren bringen, weil Spring, sobald der Controller zurückkehrt, cleanupMultipart() im CommonsMultipartResolver aufruft. Da das resolveLazily-Flag auf "false" gesetzt ist, wird beim Aufrufen von cleanupMultipart() damit begonnen, die mehrteiligen Dateien aufzulösen und zu initialisieren. Dies führt zu einer Wettlaufsituation zwischen dem Aufruf von "request.getFile (" theFile ");" in der Runnable und der cleanupMultipart() -Aufruf führt schließlich zu einer Ausnahme.

Wer hat irgendwelche Ideen? Repariere ich hier irgendeine Art von HTTP-Vertrag, indem ich eine asynchrone Backend-Dateiverarbeitung durchführen möchte.

+0

Commention auf meinem eigenen Beitrag. Ich habe die folgenden Blogs gefunden, die helfen könnten, eine Lösung zu finden. http://blog.springsource.org/2012/05/06/spring-mvc-3-2-preview-introducing-servlet-3-async-support/ https://blogs.oracle.com/ enterprisetechnts/entry/asynchronous_support_in_servlet_3 Ich poste zurück, wenn ich mit einem Arbeitsbeispiel komme. – CAL5101

Antwort

5

Die HTTP-Anfrage wird bereits in einem eigenen Thread ausgeführt, und der Client kann mehrere Anfragen parallel asynchron durchführen. Sie müssen also keinen neuen Thread starten. Speichern/bearbeiten Sie die Datei wie gewohnt im Hauptthread. Mache 'asynchrone Datei-Upload' nur auf der Client-Seite.

Außerdem sollten Sie HTTP-Antwort nur senden, wenn Sie die Eingabe verarbeitet haben. Ich meine, Sie können den Eingabe-Header nicht lesen, eine HTTP-Antwort erstellen und weiterhin Daten aus dem Browser lesen. Verbraucht Input -> Verarbeite es -> Sende Output, so funktioniert das HTTP 1/1.1-Protokoll.

Wenn Sie eine Ticketnummer müssen zum Hochladen zu senden, können Sie es vor dem eigentlichen Upload erstellen, durch einen zweistufigen Upload verwenden, wie:

  • Ajax-GET-Anfrage Ticketnummer
  • POST ein erhalten Dateiinhalt und Ticket-Nummer (aus dem vorherigen Schritt erhalten)
  • + ajax-GET aktuellen Status Ticket erhalten, zu jeder Zeit später, async
+0

zustimmen.Ich möchte nur eine wenig Klärung hinzuzufügen: was user1404399 fragt ist, wie man „Asynchron-Upload“ von einem neuen Thread auf Server-Seite, während der richtige Weg, um dieses Problem zu handhaben ist Ajax-Beitrag von Javascript mit der Griff-Upload Aktion zu machen, und dem Benutzer den Fortschritt melden, indem er eine andere Aktion abfragt. Ist das deine Idee? –

+0

@ HoàngLong rechts –

+0

Danke für die Antworten Jungs. Ich hatte das gute Gefühl, dass dies nicht möglich war, aber ich wurde gedrängt, eine Lösung zu finden. Wir haben nichts implementiert, sondern nur einen normalen Datei-Upload. P.S. Ich habe meinen Anzeigenamen auf etwas lesbarer aktualisiert als user1404399 – CAL5101