当前位置: 首页 > 知识库问答 >
问题:

Spring MockMvc多部分读取zip文件IOException:流关闭

晏鸿畅
2023-03-14

我想测试一个Multipart控制器,它读取zip文件并遍历所有条目。这是执行此操作的控制器方法:

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

    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");

    if (!file.isEmpty()) {
        byte[] bytes = file.getBytes();

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

        ZipEntry entry = null;
        while ((entry = zis.getNextEntry()) != null) {

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

        }


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

现在,相关测试如下:

@测试公共无效testProcessingGeneralUpload()抛出异常{

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

MockMultipartFile firstFile = new MockMultipartFile(
        "file", "filename.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, template.getInputStream());

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

}

我得到的错误是:

java.io.IOException: Stream closed
    at java.util.zip.ZipInputStream.ensureOpen(ZipInputStream.java:67)
    at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:116)
    at com.touchcorp.touchpoint.resource.mvc.ContentUploadResource.handleGeneralUpload(ContentUploadResource.java:221)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:62)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:170)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:137)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:141)
    at com.touchcorp.touchpoint.resource.mvc.ContentUploadResourceUnitTest.testProcessingGeneralUpload(ContentUploadResourceUnitTest.java:190)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

问题是我似乎无法在正确的状态下构造MockMultipartFile。我想一个解决方法是将所有处理逻辑重构到一个单独的方法中,并在容器外进行测试,但我宁愿将所有逻辑都保留在一个地方。谁能告诉我如何实例化MockMultipartFile,使其能够读取content.zip?

共有1个答案

杭柏
2023-03-14

找到答案后,我需要更换线路:

MockMultipartFile firstFile = new MockMultipartFile(
        "file", "filename.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, template.getInputStream());

与:

MockMultipartFile firstFile = new MockMultipartFile(
     "file", "filename.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, new ZipInputStream(template.getInputStream()));

虽然,我现在有一个新问题:文件是空的,换句话说:文件。控制器中的isEmpty()返回true。

编辑

这也有一个答案,我再次将这句话替换为:

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

其中extractFile是:

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

似乎我需要读取流中的所有数据,以便填充字节。然而,它仍然没有解决,但请参阅:如何从spring mvc multipartfile进入zipinputstream进行讨论。

 类似资料:
  • 问题内容: 我有多个包含不同类型的txt文件的zip文件。如下所示: 如何使用pandas读取每个文件而不提取它们? 我知道每个zip文件是否为1个文件,我可以对read_csv使用压缩方法,如下所示: 任何有关如何执行此操作的帮助都将非常有用。 问题答案: 你可以传递到构建从包装成一个多文件一个CSV文件。 码: 将所有内容读入字典的示例:

  • 我试图创建一个简单的java程序,从zip文件中读取并提取文件内容。Zip文件包含3个文件(txt、pdf、docx)。我需要阅读所有这些文件的内容,为此我正在使用ApacheTika。 有人能帮我实现这个功能吗。到目前为止,我已经试过了,但没有成功 代码片段

  • 在通过CLI部署EAR时,会出现以下错误: 然而,Netbeans在IDE中部署了同样的EAR fine。 我认为问题是EJB模块依赖于作为JAR构建的远程接口。这个JAR包含在EAR中,但我不认为这就足够了。我尝试将其放置在和中,但是,这并不能解决或更改异常。 问题是JAR需要在glassfish上可用吗?在这个EJB实现这个接口之前,它部署得很好。(EJB实现远程接口的原因是,EJB可用于we

  • 问题内容: 我的情况是我有一个包含一些文件(txt,png,…)的zip文件,我想直接按它们的名称读取它,我已经测试了以下代码,但没有结果(NullPointerExcepion): resources 是一个包, zipfile 是一个zip文件。 问题答案: 如果您可以确定您的zip文件永远不会打包在另一个jar中,则可以使用以下方法: 要么: 否则,您的选择是: 使用ZipInputStre

  • 我有一个zip文件(在一个jar文件中),我想读取init。我知道我可以使用getResourceAsStream(…)轻松读取txt文件,避免“URI不分层”错误。但现在确定我该如何为zip文件做到这一点。 下面是我的代码,但当我将代码导出到runnable jar并运行它时,它会抛出“URI非层次错误”。

  • 问题内容: 我有一个zip存档,其中包含一堆纯文本文件。我想解析每个文本文件的数据。到目前为止,这是我写的内容: 我需要一个RandomAccessFile来做到这一点吗?我在拥有ZipInputStream的地方迷路了。 问题答案: 不,您不需要。首先获取此zip文件条目的数据: 然后将其包装为(从二进制解码为文本)和a (一次读取一行): 然后像往常一样从中读取行。像往常一样将所有适当的位包装