如何从Spring MVC Multipartfile进入zipinputstream [英] How to go from spring mvc multipartfile into zipinputstream

查看:100
本文介绍了如何从Spring MVC Multipartfile进入zipinputstream的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Spring MVC控制器,它接受MultipartFile,它将是一个zip文件.问题是我似乎无法从那里转到ZipInputStream或ZipFile,这样我才能遍历所有条目.它会过早关闭流,生成一个空文件,或者在以下情况下,zipInputStream.getNextEntry()返回null.

I have a Spring MVC controller that accepts a MultipartFile, which will be a zip file. The problem is I can't seem to go from that to a ZipInputStream or ZipFile, so that I can go through the entries. It either closes the stream prematurely, produces an empty file, or as in the case below, zipInputStream.getNextEntry() returning null.

这是我的MVC控制器:

This is my MVC controller:

@RequestMapping(value = "/content/general-import", method = RequestMethod.POST)
public ModelAndView handleGeneralUpload(
                                  @RequestParam("file") MultipartFile file) throws IOException {

    // hard code the signature for the moment
    String signature = "RETAILER_GROUP:*|CHANNEL:*|LOCALE:de-AT|INDUSTRY:5499";

    LOG.info("Processing file archive: {} with signature: {}.", file.getName(), signature);

    ModelAndView mav = new ModelAndView();
    mav.setViewName("contentUpload");

    LOG.debug("File={} is empty={}.", file.getName(), file.isEmpty());
    if (!file.isEmpty()) {

        processFileZipEntry(file, signature);


        mav.addObject("form", UploadViewModel.make("/content/general-import", "Updated content with file"));

        return mav;
    } else {

        mav.addObject("form", UploadViewModel.make("/content/general-import", "Could not update content with file"));

        return mav;
    }
}

它委托以下方法进行处理:

It delegates to the following method for processing:

protected void processFileZipEntry(MultipartFile file, String signature) throws IOException {
    byte[] bytes = file.getBytes();
    LOG.debug("Processing archive with bytes={}.", file.getBytes().length);

    ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes));

    LOG.debug("Processing archive with size={}.", file.getSize());
    ZipEntry entry = null;
    while ((entry = zis.getNextEntry()) != null) {

        LOG.debug("Processing file={} is directory?={}.", entry.getName(), entry.isDirectory());
        // process each file, based on what it is and whether its a directory etc.
        if (!entry.isDirectory()) {
            // if the entry is a file, extract it
            LOG.debug("Processing entry: {}",entry.getName());

            int length = (int) entry.getSize();

            Content contentToSave = null;
            if(entry.getName().contains("gif")) {
                contentToSave = Content.makeImage(entry.getName(), Content.GIF, signature, getBytesFrom(zis, "gif"));
            } else if (entry.getName().contains("png")) {
                contentToSave = Content.makeImage(entry.getName(), Content.PNG, signature, getBytesFrom(zis, "png"));
            } else if (entry.getName().contains("jpeg")) {
                contentToSave = Content.makeImage(entry.getName(), Content.JPEG, signature, getBytesFrom(zis, "jpeg"));
            } else if (entry.getName().contains("json")) {
                contentToSave = Content.makeFile(entry.getName(), Content.JSON, signature, getStringFrom(zis, length));
            } else if (entry.getName().contains("js")) {
                contentToSave = Content.makeFile(entry.getName(), Content.JS, signature, getStringFrom(zis, length));
            } else if (entry.getName().contains("css")) {
                contentToSave = Content.makeFile(entry.getName(), Content.CSS, signature, getStringFrom(zis, length));
            }

            Content contentAleadyThere = contentService.fetch(entry.getName());
            if(contentAleadyThere != null) {
                LOG.warn("Replacing file: {} with uploaded version.", contentToSave.getName());
            }

            contentService.put(contentToSave);
            LOG.info("Persisted file: {} from uploaded version.", contentToSave.getName());
        }

    }
}

基本上,在这个排列中,文件字节存在,但是没有条目(zis.getNextEntry()不存在.我可以看到zip文件包含文件,并且byte []的大小约为3MB)东西,所以流媒体一定出问题了.有人能从MultipartFile转到ZipFile或ZipInputStream吗?

Basically, in this permutation, the file bytes are there, but there are no entries (zis.getNextEntry() does not exist. I can see that the zip file contains files, and the byte[] has about 3MB worth of stuff, so something must be going wrong with the streaming. Does anyone have a recipe for going from MultipartFile to ZipFile or ZipInputStream?

编辑

为了给您更多的信息,我使用MockMvc对此代码进行了测试

To give you more information, I have a test harnass around this code, by using a MockMvc

@Test
public void testProcessingGeneralUpload() throws Exception {

    Resource template = wac.getResource("classpath:lc_content/content.zip");

    System.out.println("template content length: " + template.contentLength());
    System.out.println("template path: " + template.getFile().getPath());
    System.out.println("template filename: " + template.getFilename());



    MockMultipartFile firstFile = new MockMultipartFile(
            "file", "content.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, extractFile(template.getFile()));

    MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.fileUpload("/content/general-import")
            .file(firstFile))
            .andExpect(status().isOk())
            .andExpect(view().name("contentUpload"))
            .andExpect(model().attributeExists("form")).andReturn();

    // processing assertions
    ModelMap modelMap = mvcResult.getModelAndView().getModelMap();
    Object object = modelMap.get("form");
        assertThat(object, is(not(nullValue())));
        assertThat(object, is(instanceOf(UploadViewModel.class)));
    UploadViewModel addModel = (UploadViewModel) object;
        assertThat(addModel.getMessage(), is(notNullValue()));
    assertThat(addModel.getPostUrl(), is(notNullValue()));
    assertThat(addModel.getPostUrl(), is("/content/general-import"));
    assertThat(addModel.getMessage(), is("Updated content with file"));

    // persistence assertions

    assertThat(contentDao.findByName("/content/control/basket-manager.js"), is(notNullValue()) );

}

extractFile方法如下:

The extractFile method is as follows:

private byte[] extractFile(File zipFile) throws IOException {

    ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile));
    System.out.println("length of file: " + zipFile.length());

    byte[] output = null;

    try {
        byte[] data = new byte[(int)zipFile.length()];
        zipIn.read(data);
        zipIn.close();

        output = data;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return output;

}

它产生的字节长度是3617817,这是我期望的大小,并且将其馈送到此问题顶部的controller方法中.

The length of bytes it produces is 3617817, which is the size I expect, and this is fed into the controller method at the top of this question.

我继续解决该问题.该文件的大小是正确的,它是一个压缩文件(可以通过OS完美解压缩),但是没有ZipEntry枚举.

I have continued working the problem. The size of the file is correct, it is a zipped file (it unpacks via the OS perfectly), and yet no ZipEntry enumeration.

推荐答案

对于初学者来说,我会重写一些代码,而不用额外的byte []在内存中处理事务.

I would for starters rewrite some of the code instead of doing things in memory with additional byte[].

您正在使用Spring的Resource类,所以为什么不简单地使用getInputStream()方法构造MockMultipartFile,就像您要上载该文件一样.

You are using Spring's Resource class so why not simply use the getInputStream() method to construct the MockMultipartFile as you want to upload that file.

Resource template = wac.getResource("classpath:lc_content/content.zip");
MockMultipartFile firstFile = new MockMultipartFile(
        "file", "content.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, template.getInputStream());

ZipInputStream与您的上传处理代码相同,也可以在另一个InputStream上构建,该InputStream也由MultipartFile界面提供.

The same for your upload processing code the ZipInputStream can also be constructed on another InputStream which is also provided by the MultipartFile interface.

protected void processFileZipEntry(MultipartFile file, String signature) throws IOException {

    LOG.debug("Processing archive with size={}.", file.getSize());
    ZipInputStream zis = new ZipInputStream(file.getInputStream());

不是第一次与byte[]纠缠会带来问题.我还隐约记得ZipInputStream的一些问题,这些问题导致我们使用ZipFile,但是为此,您首先必须使用MultipartFile上的transferTo方法将文件存储在临时目录中.

Wouldn't be the first time that jugling around with byte[] gives a problem. I also vaguely recall some issues with ZipInputStream which lead us to use ZipFile but for this you will first have to store the file in a temp directoy using the transferTo method on MultipartFile.

File tempFile = File.createTempFile("upload", null);
file.transferTo(tempFile);
ZipFile zipFile = new ZipFle(tempFile);
// Proces Zip
tempFile.delete();

这篇关于如何从Spring MVC Multipartfile进入zipinputstream的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆