下载多个文件 Java Spring

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36886141/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:58:41  来源:igfitidea点击:

Download Multiple files Java Spring

javaspringhttpdownload

提问by Whitefret

I am trying to download multiple file with one http get request in my spring-mvc application.

我试图在我的 spring-mvc 应用程序中使用一个 http get 请求下载多个文件。

I have looked at other posts, saying you could just zip the file and send this file but it's not ideal in my case, as the file are not in direct access from the application. To get the files I have to query a REST interface, which streams the file from either hbase or hadoop.

我看过其他帖子,说你可以压缩文件并发送这个文件,但在我的情况下并不理想,因为该文件不能从应用程序直接访问。要获取文件,我必须查询 REST 接口,该接口从 hbase 或 hadoop 流式传输文件。

I can have files bigger than 1 Go, so downloading the files into a repository, zipping them and sending them to the client would be too long. (Considering that the big file are already zip, zipping won't compress them).

我可以拥有大于 1 Go 的文件,因此将文件下载到存储库、压缩它们并将它们发送到客户端会太长。(考虑到大文件已经是 zip,压缩不会压缩它们)。

I saw hereand therethat you can use multipart-responseto download multiple files at once, but I can't get any result. Here is my code:

我在这里那里看到您可以multipart-response一次下载多个文件,但我无法得到任何结果。这是我的代码:

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();
}   

The weird part is that I get different result depending on the navigator. Nothing happends in Chrome (looked at the console) and in Firefox, I got a prompt asking to download for each file but it doesn't have the right type nor the right name (nothing in console either).

奇怪的是,根据导航器的不同,我得到了不同的结果。在 Chrome(查看控制台)和 Firefox 中没有发生任何事情,我收到提示要求下载每个文件,但它没有正确的类型和正确的名称(控制台中也没有)。

Is there any bug in my code? If no, is there any alternative?

我的代码中是否有任何错误?如果没有,有没有其他选择?

Edit

编辑

I also saw this post: Unable to send a multipart/mixed request to spring MVC based REST service

我还看到了这篇文章:无法向基于 Spring MVC 的 REST 服务发送多部分/混合请求

Edit 2

编辑 2

firefox result

火狐结果

The content of this file is what I want, but why can't I get the right name and why can't chrome download anything?

这个文件的内容就是我想要的,但是为什么我不能得到正确的名字,为什么chrome不能下载任何东西?

回答by We are Borg

This is the way you can do the download via zip :

这是您可以通过 zip 进行下载的方式:

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 method for downloading zip :

下载 zip 的控制器方法:

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

Have fun, incase of doubt, lemme know.

玩得开心,以防万一,让我知道。

Update

更新

Byte-array in a ZIP file. You can use this code in a loop as in the first method I gave :

ZIP 文件中的字节数组。您可以在循环中使用此代码,就像我给出的第一种方法一样:

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();
}

回答by Kuncheria

You can do it using the multipart/x-mixed-replace content type. You can add this like response.setContentType("multipart/x-mixed-replace;boundary=END");and loop through the files and write each to the response output stream. You can check out this examplefor reference.

您可以使用 multipart/x-mixed-replace 内容类型来完成。您可以添加类似的内容response.setContentType("multipart/x-mixed-replace;boundary=END");并遍历文件并将每个文件写入响应输出流。您可以查看此示例以供参考。

Another approach is to create a REST end point that will let you download one single file and then repeatedly call this end point for each file individually.

另一种方法是创建一个 REST 端点,让您下载一个文件,然后为每个文件单独重复调用此端点。