2014-06-26 75 views
0

我想測試一個讀取zip文件並遍歷所有條目的Multipart控制器。下面是做它的控制器的方法:彈出MockMvc多部分讀取壓縮文件IOException:流關閉

@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 公共無效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?

回答

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

雖然,我現在有一個新的問題:該文件是空的,換句話說:文件控制器中的.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討論。

+0

我最近找到了一個解決方案,不要使用'ZipInputStream',只是將'InputStream'傳遞給'MockMultipartFile' – Sean