2016-04-27 3 views
2

Ich versuche, mehrere Dateien mit einer http get Anfrage in meiner Spring-Mvc-Anwendung herunterladen.Laden Sie mehrere Dateien herunter Java Spring

Ich habe andere Beiträge angeschaut und gesagt, Sie könnten einfach die Datei zippen und diese Datei senden, aber es ist nicht ideal in meinem Fall, da die Datei keinen direkten Zugriff von der Anwendung hat. Um die Dateien zu bekommen, muss ich eine REST-Schnittstelle abfragen, die die Datei entweder von hbase oder von hadoop streamt.

Ich kann Dateien größer als 1 Go haben, also die Dateien in ein Repository herunterladen, sie zippen und an den Client senden, wäre zu lang. (Wenn man bedenkt, dass die große Datei bereits zip ist, werden sie beim Komprimieren nicht komprimiert).

Ich sah here und there, dass Sie multipart-response verwenden können, um mehrere Dateien auf einmal zu downloaden, aber ich kann kein Ergebnis erhalten. Hier ist mein Code:

String boundaryTxt = "--AMZ90RFX875LKMFasdf09DDFF3"; 
response.setContentType("multipart/x-mixed-replace;boundary=" + boundaryTxt.substring(2)); 
ServletOutputStream out = response.getOutputStream(); 

// write the first boundary 
out.write(("\r\n"+boundaryTxt+"\r\n").getBytes()); 

String contentType = "Content-type: application/octet-stream\n"; 

for (String s:files){ 
    System.out.println(s); 
    String[] split = s.trim().split("/"); 
    db = split[1]; 
    key = split[2]+"/"+split[3]+"/"+split[4]; 
    filename = split[4]; 

    out.write((contentType + "\r\n").getBytes()); 
    out.write(("\r\nContent-Disposition: attachment; filename=" +filename+"\r\n").getBytes()); 

    InputStream is = null; 
    if (db.equals("hadoop")){ 
     is = HadoopUtils.get(key); 
    } 
    else if (db.equals("hbase")){ 
     is = HbaseUtils.get(key); 
    } 
    else{ 
     System.out.println("Wrong db with name: " + db); 
    } 
    byte[] buffer = new byte[9000]; // max 8kB for http get 
    int data; 
    while((data = is.read(buffer)) != -1) { 
     out.write(buffer, 0, data); 
    } 
    is.close(); 

    // write bndry after data 
    out.write(("\r\n"+boundaryTxt+"\r\n").getBytes()); 
    response.flushBuffer(); 
    } 
// write the ending boundary 
out.write((boundaryTxt + "--\r\n").getBytes()); 
response.flushBuffer(); 
out.close(); 
} 

Der komische Teil ist, dass ich unterschiedliche Ergebnisse je nach Navigator bekommen. Nichts passiert in Chrome (schaute auf die Konsole) und in Firefox, ich bekam eine Aufforderung zum Download für jede Datei, aber es hat nicht den richtigen Typ noch den richtigen Namen (nichts in der Konsole auch).

Gibt es einen Fehler in meinem Code? Wenn nein, gibt es eine Alternative?

bearbeiten

ich auch diesen Beitrag gesehen: Unable to send a multipart/mixed request to spring MVC based REST service

bearbeiten 2

firefox result

Der Inhalt dieser Datei ist es, was ich will, aber warum nicht Ich bekomme den richtigen Namen und warum kann ich nichts herunterladen?

+0

Sie können die Download-Anforderungen in JS wiederholen, und nach jeder Anfrage wird ein neuer Download ausgelöst. Ich denke, das scheint einfacher zu sein als herumzuhacken, um mehrere Downloads auszulösen. –

+0

@WeareBorg Ich habe nur ein Grundwissen in js, kannst du mir ein paar Ressourcen dafür geben? – Whitefret

+0

Leider nein, ich bin ein Backend-Entwickler, kenne JS nicht einmal. Ich kann Ihnen Code für ZIP-Download geben, wenn Sie in Java wollen, dass ich ... –

Antwort

2

Dies ist die Art und Weise Sie den Download über zip tun können:

try { 
     List<GroupAttachments> groupAttachmentsList = attachIdList.stream().map(this::getAttachmentObjectOnlyById).collect(Collectors.toList()); // Get list of Attachment objects 
      Person person = this.personService.getCurrentlyAuthenticatedUser(); 
      String zipSavedAt = zipLocation + String.valueOf(new BigInteger(130, random).toString(32)); // File saved location 
      byte[] buffer = new byte[1024]; 
      FileOutputStream fos = new FileOutputStream(zipSavedAt); 
      ZipOutputStream zos = new ZipOutputStream(fos); 

       GroupAttachments attachments = getAttachmentObjectOnlyById(attachIdList.get(0)); 

        for (GroupAttachments groupAttachments : groupAttachmentsList) { 
          Path path = Paths.get(msg + groupAttachments.getGroupId() + "/" + 
            groupAttachments.getFileIdentifier()); // Get the file from server from given path 
          File file = path.toFile(); 
          FileInputStream fis = new FileInputStream(file); 
          zos.putNextEntry(new ZipEntry(groupAttachments.getFileName())); 
          int length; 

          while ((length = fis.read(buffer)) > 0) { 
           zos.write(buffer, 0, length); 
          } 
          zos.closeEntry(); 
          fis.close(); 

        zos.close(); 
        return zipSavedAt; 
      } 
     } catch (Exception ignored) { 
     } 
     return null; 
    } 

Controller-Methode für Zip-Download:

@RequestMapping(value = "/URL/{mode}/{token}") 
    public void downloadZip(HttpServletResponse response, @PathVariable("token") String token, 
          @PathVariable("mode") boolean mode) { 
     response.setContentType("application/octet-stream"); 
     try { 
      Person person = this.personService.getCurrentlyAuthenticatedUser(); 
      List<Integer> integerList = new ArrayList<>(); 
      String[] integerArray = token.split(":"); 
      for (String value : integerArray) { 
       integerList.add(Integer.valueOf(value)); 
      } 
      if (!mode) { 
       String zipPath = this.groupAttachmentsService.downloadAttachmentsAsZip(integerList); 
       File file = new File(zipPath); 
       response.setHeader("Content-Length", String.valueOf(file.length())); 
       response.setHeader("Content-Disposition", "attachment; filename=\"" + person.getFirstName() + ".zip" + "\""); 
       InputStream is = new FileInputStream(file); 
       FileCopyUtils.copy(IOUtils.toByteArray(is), response.getOutputStream()); 
       response.flushBuffer(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

Viel Spaß, Incase Zweifel, wissen Lemme.

aktualisieren

Byte-Array in einer ZIP-Datei. Sie können diesen Code in einer Schleife wie in der ersten Methode, die ich gab:

public static byte[] zipBytes(String filename, byte[] input) throws IOException { 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ZipOutputStream zos = new ZipOutputStream(baos); 
    ZipEntry entry = new ZipEntry(filename); 
    entry.setSize(input.length); 
    zos.putNextEntry(entry); 
    zos.write(input); 
    zos.closeEntry(); 
    zos.close(); 
    return baos.toByteArray(); 
}