如何使用 Spring MockMvc PUT 多部分/表单数据?

问题描述 投票:0回答:5

我有一个带有

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

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

我想用

MockMvc
来测试它。不幸的是,
MockMvcRequestBuilders.fileUpload
本质上创建了一个
MockMultipartHttpServletRequestBuilder
的实例,它有一个
POST
方法:

super(HttpMethod.POST, urlTemplate, urlVariables)

编辑: 我当然可以 我不能创建我自己的

MockHttpServletRequestBuilder
实现,比如说

public MockPutMultipartHttpServletRequestBuilder(String urlTemplate, Object... urlVariables) {
    super(HttpMethod.PUT, urlTemplate, urlVariables);
    super.contentType(MediaType.MULTIPART_FORM_DATA);
}

因为

MockHttpServletRequestBuilder
有一个包本地构造函数。

但是我想知道是否有更方便的有什么方法可以做到这一点,可能我错过了一些现有的类或方法来做到这一点?

java spring multipartform-data spring-test-mvc mockmvc
5个回答
92
投票

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

我自己也遇到了同样的问题。尽管我对 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.multipart("/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().isOk());

效果就像一个魅力!


5
投票

不幸的是,Spring MVC Test 目前不支持这一点,除了创建您自己的自定义

MockPutMultipartHttpServletRequestBuilder
和从标准实现中复制粘贴代码之外,我没有看到其他解决方法。

值得一提的是,Spring MVC 默认也不支持

PUT
文件上传请求。多部分解析器经过硬编码,只接受
POST
文件上传请求——既支持 Apache Commons 又支持标准 Servlet API。

如果您希望 Spring 另外支持

PUT
请求,请随时在 Spring 的 JIRA 问题跟踪器中 开票


5
投票

翻译 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)

0
投票

您可以同时通过

foo
file

尝试重写你的控制器,如:

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

0
投票

我认为这个问题已经在 V 5.3.22 中修复了

/**
 * Variant of {@link #multipart(String, Object...)} that also accepts an
 * {@link HttpMethod}.
 * @param httpMethod the HTTP method to use
 * @param urlTemplate a URL template; the resulting URL will be encoded
 * @param uriVariables zero or more URI variables
 * @since 5.3.22
 */
public static MockMultipartHttpServletRequestBuilder multipart(HttpMethod httpMethod, String urlTemplate, Object... uriVariables) {
    return new MockMultipartHttpServletRequestBuilder(httpMethod, urlTemplate, uriVariables);
}
© www.soinside.com 2019 - 2024. All rights reserved.