【问题标题】:How to Post multipart/form-data for a File Upload using SpringMVC and MockMVC如何使用 Spring MVC 和 MockMVC 为文件上传发布多部分/表单数据
【发布时间】:2013-12-21 18:55:12
【问题描述】:

我创建了一个使用 javax.ws.rs 效果很好的照片上传器。这是它的签名和基本要点:

@POST
@Path("/upload/photo")
@Consumes("multipart/form-data")
@Produces("application/json")
public String uploadPhoto(InputStream stream){
        try {
            int read = 0;
            FileOutputStream fos = new FileOutputStream(file);
            CountingOutputStream out = new CountingOutputStream(fos);
            byte[] bytes = new byte[MAX_UPLOAD_SIZE];

            while ((read = stream.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            out.flush();
            out.close();
        } catch (IOException e) {
            // TODO throw!
            e.printStackTrace();
        }
    //...
}

我可以像这样使用 apache.commons.httpClient 库对此进行测试:

    @Test
    public void testUpload() {

        int statusCode = 0;
        String methodResult = null;

        String endpoint = SERVICE_HOST + "/upload/photo";

        PostMethod post = new PostMethod(endpoint);

        File file = new File("/home/me/Desktop/someFolder/image.jpg");

        FileRequestEntity entity = new FileRequestEntity(file, "multipart/form-data");

        post.setRequestEntity(entity);

        try {
            httpClient.executeMethod(post);
            methodResult = post.getResponseBodyAsString();
        } catch (HttpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        statusCode = post.getStatusCode();

        post.releaseConnection();
            //...
    }

这很好用!问题是应用程序的其余部分是使用 Spring MVC 编写的。当我使用 Spring Mock MVC 测试框架时,程序只是挂起(显示在这个下面的代码 sn-p 中)。这是上传者的SpringMVC代码:

@ResponseBody
@RequestMapping(    produces="application/json",
                    consumes="multipart/form-data",
                    method=RequestMethod.POST,
                    value="/photo")
public String uploadPhoto(@RequestPart("file") MultipartFile multipartFile){

            try {
                int read = 0;
                FileOutputStream fos = new FileOutputStream(file);
                CountingOutputStream out = new CountingOutputStream(fos);
                byte[] bytes = new byte[MAX_UPLOAD_SIZE];

                while ((read = multipartFile.getInputStream().read(bytes)) != -1) {
                    out.write(bytes, 0, read);
                }

                out.flush();
                out.close();

            } catch (IOException e) {
                // TODO throw!
                e.printStackTrace();
            }
            //...
}

下面是我使用 Spring Mock MVC 实现的测试。我认为问题与使用 fileUpload(...) 有关。有没有办法使用普通的 post(..) 来测试,就像我可以使用 apache 一样?我更喜欢使用 InputStream 作为参数,避免使用 MultipartFile。

@Test
public void testUpload() throws Exception {

    String endpoint = BASE_URL + "/upload/photo";

    FileInputStream fis = new FileInputStream("/home/me/Desktop/someFolder/image.jpg");
    MockMultipartFile multipartFile = new MockMultipartFile("file", fis);

    mockMvc.perform(fileUpload(endpoint)
            .file(multipartFile)
            .contentType(MediaType.MULTIPART_FORM_DATA))
            .andExpect(status().isOk());

}

理想情况下,我想使用 Spring MVC 和 Spring Mock MVC 框架,但我提供的代码只是挂在 while 语句上。就在 Spring 测试中使用 fileUpload 方法而言,我所做的是否正确?任何建议表示赞赏。

【问题讨论】:

  • 冗长的代码示例...某处出了点问题...您的实际问题是什么? -1

标签: java rest spring-mvc


【解决方案1】:
  1. 要向模拟发布请求添加内容,请使用 content(bytes[])
  2. 媒体类型参数边界是必要的

此外,使用来自 java.io 的普通旧 InputStream 作为上传方法的参数是安全的,并且仍然在请求中使用 MockMultipartFile。

@Test
public void testUpload() throws Exception {

            String endpoint = BASE_URL + "/upload/photo";

            FileInputStream fis = new FileInputStream("/home/me/Desktop/someDir/image.jpg");
            MockMultipartFile multipartFile = new MockMultipartFile("file", fis);

            HashMap<String, String> contentTypeParams = new HashMap<String, String>();
            contentTypeParams.put("boundary", "265001916915724");
            MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);

            mockMvc.perform(
                    post(endpoint)
                    .content(multipartFile.getBytes())
                    .contentType(mediaType))
                    .andExpect(status().isOk());
}

【讨论】:

  • 也许这行得通,但我认为多部分消息的每个部分都应该以边界开头,在你的情况下是--265001916915724
  • 为什么不使用 MockMvcRequestBuilders.fileUpload 而不是 post?
  • 为什么要将 Jax-RS 与 Spring MVC 结合在一个 Web 应用程序中?这对我来说没有意义
  • 这段代码不适合我,你在执行调用中将“文件”传递到哪里?当您仅使用 mockMvc.perform 中的内容时,它将不断抱怨缺少的 @RequestPart("file"): .content(multipartFile.getBytes())
  • 非常感谢。它甚至适用于 org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload 流上传!
【解决方案2】:

MockMvcRequestBuilders.fileUpload:

@Test
public void uploadTest() throws Exception {
    String endpoint = "/service/productsale/5/upload";
    FileInputStream fis = new FileInputStream("E:\\test\\test.jpg");
    MockMultipartFile multipartFile = new MockMultipartFile("file",fis);

    mockMvc.perform(MockMvcRequestBuilders.fileUpload(endpoint).file(multipartFile))
            .andExpect(MockMvcResultMatchers.model().attributeExists("imageVo"))
            .andDo(print())
            .andExpect(status().isOk());
}

【讨论】:

  • > 注意,从 Spring 5.0 开始,MockMvcRequestBuilders.fileUpload() 已被弃用,取而代之的是 MockMvcRequestBuilders.multipart() 方法。 Link to article
【解决方案3】:

通过引用document,下面的代码可以更简单。

@Test
public void testFileUpload() throws Exception {
    FileInputStream input = new FileInputStream("/Downloads/WX.png");
    MockMultipartFile file = new MockMultipartFile(
            "image",
            "WX20180207-134704@2x.png",
            "image/png",
            input);
    this.mockMvc
            .perform(
                multipart("/api/note/image/create")
                        .file(file)
                        .header("Authorization", "BearereyJhbGciOiJIUzUxMiJ9")
            );
}

【讨论】:

    【解决方案4】:

    这个链接帮助了我:https://samerabdelkafi.wordpress.com/2014/08/03/spring-mvc-full-java-based-config/

    更具体地说,此配置: @Override

    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
    

    【讨论】:

      猜你喜欢
      • 2015-03-29
      • 2016-11-29
      • 1970-01-01
      • 2013-12-08
      • 2014-08-18
      • 1970-01-01
      • 2014-09-29
      • 2020-03-14
      • 2014-09-29
      相关资源
      最近更新 更多