如何使用Spring MockMvc输出multipart / form-data?

时间:2016-07-25 15:24:11

标签: java spring multipartform-data spring-test-mvc mockmvc

我有PUT方法的控制器方法,它接收多部分/表单数据:

   @RequestMapping(value = "/putIn", method = RequestMethod.PUT)
   public Foo updateFoo(HttpServletRequest request,
                           @RequestBody Foo foo,
                           @RequestParam("foo_icon") MultipartFile file) {
    ...
   }

我希望使用MockMvc对其进行测试。不幸的是,MockMvcRequestBuilders.fileUpload基本上创建了MockMultipartHttpServletRequestBuilder的{​​{1}}方法实例:

POST

修改 当然我可以 我不能创建我自己的super(HttpMethod.POST, urlTemplate, urlVariables) 实现,比如说

MockHttpServletRequestBuilder

因为public MockPutMultipartHttpServletRequestBuilder(String urlTemplate, Object... urlVariables) { super(HttpMethod.PUT, urlTemplate, urlVariables); super.contentType(MediaType.MULTIPART_FORM_DATA); } 具有包本地构造函数。

但我想知道是否更方便有没有办法做到这一点,可能是我错过了一些现有的课程或方法吗?

4 个答案:

答案 0 :(得分:32)

是的,有办法,而且也很简单!

我自己遇到了同样的问题。虽然我对Sam Brannen的回答感到沮丧,但现在看来Spring MVC支持PUT文件上传,因为我可以使用Postman(我正在使用Spring Boot 1.4.2)进行这样的请求。所以,我一直在挖掘,发现唯一的问题是MockMultipartHttpServletRequestBuilder返回的MockMvcRequestBuilders.fileUpload()将方法硬编码为“POST”。然后我发现了with()方法......

这让我想出了这个简洁的小技巧,迫使MockMultipartHttpServletRequestBuilder无论如何都要使用“PUT”方法:

    MockMultipartFile file = new MockMultipartFile("data", "dummy.csv",
            "text/plain", "Some dataset...".getBytes());

    MockMultipartHttpServletRequestBuilder builder =
            MockMvcRequestBuilders.fileUpload("/test1/datasets/set1");
    builder.with(new RequestPostProcessor() {
        @Override
        public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
            request.setMethod("PUT");
            return request;
        }
    });
    mvc.perform(builder
            .file(file))
            .andExpect(status().ok());

像魅力一样!

答案 1 :(得分:4)

目前,Spring MVC测试目前不支持这一点,除了在标准实现中创建自己的自定义MockPutMultipartHttpServletRequestBuilder和复制粘贴代码之外,我还没有看到解决方法。 / p>

对于它的价值,Spring MVC默认情况下也不支持PUT文件上传请求。 Multipart解析器经过硬编码,只接受POST文件上传请求 - 包括Apache Commons和标准Servlet API支持。

如果您希望Spring另外支持PUT个请求,请随时在Spring的JIRA问题跟踪器中open a ticket

答案 2 :(得分:0)

您可以同时通过foofile

尝试像这样重写控制器:

@RequestMapping(value = "/putIn", method = RequestMethod.PUT)
public Foo updateFoo(
    HttpServletRequest request,
    @RequestPart Foo foo,
    @RequestPart MultipartFile file) {
    ...
}

测试如下:

    MockMultipartFile file = new MockMultipartFile("file", "dummy.csv",
            "text/plain", "Some dataset...".getBytes());
    // application/json if you pass json as string
    MockMultipartFile file2 = new MockMultipartFile("foo", "foo.txt",
            "application/json", "Foo data".getBytes());

    MockMultipartHttpServletRequestBuilder builder =
            MockMvcRequestBuilders.multipart("/test1/datasets/set1");
    builder.with(new RequestPostProcessor() {
        @Override
        public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
            request.setMethod("PUT");
            return request;
        }
    });
    mvc.perform(builder
            .file(file)
            .file(file2))
            .andExpect(status().ok());

答案 3 :(得分:0)

为 Kotlin 翻译 @HammerNl 答案。这对我有用。

val file = File("/path/to/file").readBytes()
val multipartFile = MockMultipartFile("image", "image.jpg", "image/jpg", file)

val postProcess = RequestPostProcessor { it.method = "PUT"; it}
mockMvc.perform(
    MockMvcRequestBuilders.multipart("/api/image/$id")
        .file(multipartFile)
        .with(postProcess))
        .andExpect(MockMvcResultMatchers.status().isOk)