0

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

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

现在相关的测试如下:

@Test public void 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?

4

1 回答 1

2

找到了答案,我需要换行:

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

虽然,我现在有一个新问题:文件是空的,换句话说:控制器中的 file.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;
}

看来我需要从流中读取所有数据才能填充字节。但是它仍然没有解决,但请参阅:How to go from spring mvc multipartfile into zipinputstream以进行讨论。

于 2014-06-26T01:55:00.863 回答