当我在 Spring Boot 应用程序中使用 CommonsMultipartResolver 时,MultipartFile 为空

Posted

技术标签:

【中文标题】当我在 Spring Boot 应用程序中使用 CommonsMultipartResolver 时,MultipartFile 为空【英文标题】:MultipartFile is null when I use CommonsMultipartResolver in my Spring Boot app 【发布时间】:2016-10-23 10:10:10 【问题描述】:

我想在我的 Spring Boot 应用程序中实现上传处理程序方法。我想使用CommonsMultipartResolver 而不是StandardServletMultipartResolver。我有以下问题:

我的控制器方法参数(文件)始终设置为空。我在HiddenHttpMethodFilter 的java 文档中看到: 在多部分 POST 请求的情况下,此过滤器需要在多部分处理之后运行,因为它固有地需要检查 POST 正文参数。

我尝试为 multipartFilter bean 设置顺序,但没有帮助。当我调试时,我看到HiddenHttpMethodFilter 总是在MultipartFilter 之前被调用。我正在使用 Spring Boot 版本 1.3.0.RELEASE 和基于 Java 的配置。如何设置HiddenHttpMethodFilterMultipartFilter 之后的顺序?

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() 
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();        
    resolver.setMaxUploadSizePerFile(52428800); 
    return resolver;


@Bean
@Order(0)
public MultipartFilter multipartFilter() 
        MultipartFilter multipartFilter = new MultipartFilter();
    multipartFilter.setMultipartResolverBeanName("multipartResolver");
    return multipartFilter;


@RequestMapping(value = "/userId", method = RequestMethod.POST)
@ResponseBody
public FileTransport create(@PathVariable("userId") Long userId,
        MultipartFile file) throws IOException 
    //return fileService.create(userId, file);
    return new FileTransport();

如果我修改方法以包含如下请求参数:

@RequestParam(name = "file", required = true) MultipartFile 文件

它抛出一个异常:'Required MultipartFile parameter 'file' is not present'。

如果我使用StandardServletMultipartResolver,一切都会按预期进行。

【问题讨论】:

因为discussed on GitHub 已经是你的MultipartFilter 的顺序是错误的。它需要小于 HiddenHttpMethodFilter 的数量级,即 -10000。如果这没有帮助,你能提供一个minimal, complete, verifiable example吗? @AndyWilkinson HiddenHttpMethodFilter 的顺序不是-10000,而是HIGHEST_PRECEDENCE+10。但即使你在它前面设置了 MultipartFilter,上传也会失败,这次是 java.io.IOException: Missing content for multipart request at org.eclipse.jetty.server.Request.extractMultipartParameters(Request.java:390)。 CommonsMultipartResolver 是否与 Spring Boot 完全兼容? @AndyWilkinson spring-boot 版本是 1.2.8。 @kpentchev 您使用的是不同版本的 Spring Boot,因此情况可能不一样。评论不是解决问题的正确地方;如果这个问题没有帮助,请提出一个新问题。 【参考方案1】:

在 Spring Boot 中要使用 CommonsMultipartResolver,您需要通过在配置中添加以下注释来禁用 MultipartAutoConfiguration:

@EnableAutoConfiguration(exclude=MultipartAutoConfiguration.class)

我的多部分解析器 bean:

 @Bean
 public MultipartResolver multipartResolver() 
     CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
     multipartResolver.setMaxUploadSize(5 * 1024 * 1024);
     return multipartResolver;
 

【讨论】:

【参考方案2】:

如果有人遇到 PUT 请求的问题,您需要扩展 CommonsMultipartResolver 并覆盖 isMultipart 方法。然后将这个新类用作 MultipartResolver bean。

public class CustomCommonsMultipartResolver extends CommonsMultipartResolver 
    @Override
    public boolean isMultipart(HttpServletRequest request) 
        String contentType = new ServletRequestContext(request).getContentType();
        if (contentType == null) 
            return false;
        
        if (contentType.toLowerCase(Locale.ENGLISH).startsWith("multipart/")) 
            return true;
        
        return false;
    

【讨论】:

【参考方案3】:

我遇到了同样的问题,下面的代码对我有用:

@Bean(name = "multipartResolver")
public CommonsMultipartResolver createMultipartResolver() 

  final CommonsMultipartResolver cmr = new CommonsMultipartResolver();
  long maxSize = parseSize(multipartConfig.getMaxFileSize());
  cmr.setMaxUploadSize(maxSize);
  cmr.setDefaultEncoding("UTF-8");
  cmr.getFileUpload().setProgressListener(
      (long pBytesRead, long pContentLength, int pItems) -> 
        LOG.info(" Uploaded % ", pBytesRead*100/pContentLength);
      );

  return cmr;


@Bean
@Order(0)
public MultipartFilter multipartFilter() 
    MultipartFilter multipartFilter = new MultipartFilter();
    multipartFilter.setMultipartResolverBeanName("multipartResolver");
    return multipartFilter;

【讨论】:

【参考方案4】:

根据this article,在使用 CommonsMultipartResolver 时正确处理一个人的多部分请求非常重要,而后者又依赖于 commons-fileupload。 我将遵循this post 中的建议。请注意我们如何设置多部分请求内容类型和内容处置。

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.MULTIPART_FORM_DATA);

    MultiValueMap<String, String> fileHeaders = new LinkedMultiValueMap<>();
    fileHeaders.add("Content-type", MediaType.TEXT_PLAIN_VALUE);
    fileHeaders.add("Content-disposition", "form-data; name=file; filename=originalFileName.txt");
    File myFile = new File(...);
    HttpEntity multipartFile = new HttpEntity<>(myFile.getBytes(), fileHeaders);

    MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
    form.add("file", multipartFile);

    ResponseEntity<String> response = new RestTemplate().postForEntity("http://localhost:8080/file/", new HttpEntity<>(form, headers), String.class);
    System.err.println(response.toString());

希望对你有帮助。

【讨论】:

【参考方案5】:

我认为他们已经解决了 Spring-Boot 1.4.2.RELEASE 版本中的问题:

@Bean
public CommonsMultipartResolver multipartResolver() 
    CommonsMultipartResolver multipart = new CommonsMultipartResolver();
    multipart.setMaxUploadSize(3 * 1024 * 1024);
    return multipart;


@Bean
@Order(0)
public MultipartFilter multipartFilter() 
    MultipartFilter multipartFilter = new MultipartFilter();
    multipartFilter.setMultipartResolverBeanName("multipartResolver");
    return multipartFilter;

还需要排除Spring-Boot的MultipartAutoConfiguration.class

@EnableAutoConfiguration(exclude = MultipartAutoConfiguration.class)

这对我有用。

【讨论】:

以上是关于当我在 Spring Boot 应用程序中使用 CommonsMultipartResolver 时,MultipartFile 为空的主要内容,如果未能解决你的问题,请参考以下文章

带有 Docker 的 Spring Boot 2.3。当我在同一个存储库中有多个 Spring Boot 应用程序时,我想为特定应用程序构建映像

Spring Boot 轮播全屏 html,css,bootstrap

Spring Boot - 当我调用 API 时,它给出 404 错误

不支持请求方法“OPTIONS”-Spring Boot 应用程序

如何在 Spring Boot 中测试 CORS?当我在 MockMvcBuilders 中尝试时,尽管 Origin 错误,它总是返回 200

Spring Boot junit测试安全应用程序