基于
SpringBoot 2.3.2.RELEASE
Spring-web 5.2.8.RELEASE
问题
做上传下载文件时,SpringBoot获取的文件是MultipartFile,不想把文件存到服务器再上传,就使用了下面的方式进行文件流的获取
MultipartFile file = 来源是浏览器;
CommonsMultipartFile cFile = (CommonsMultipartFile) file;
DiskFileItem fileItem = (DiskFileItem) cFile.getFileItem();
InputStream in = fileItem.getInputStream();
发生下面报错
java.lang.ClassCastException: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile cannot be cast to org.springframework.web.multipart.commons.CommonsMultipartFile
at com.oxye.service.impl.FileServiceImpl.store(FileServiceImpl.java:255) ~[classes/:na]
其实改成下面也行
MultipartFile file = 来源是浏览器;
InputStream in = file .getInputStream();
但上面报错问题是什么呢,我查了一些资料
org.apache.commons.fileupload包的选择
org.apache.commons.fileupload.disk.DiskFileItem
首先看,这个DiskFileItem是org.apache.commons.fileupload下面的
MultipartResolver文件上传解析接口
这个是一个接口,用于文件上传解析,从Spring3.1开始有两个实现
CommonsMultipartResolver:Apache Commons文件上传
StandardServletMultipartResolver:基于Servlet 3.0的多部分解析
spring.servlet.multipart 相关配置
这些配置后,是给StandardServletMultipartResolver用的,如果自定义了CommonsMultipartResolver,这些配置就会“失效”,或者说“不生效”,为什么呢,还是因为SpringBoot自动装配的默认选择问题,看下一节
spring.servlet.multipart.enabled=true
# 总上传数据大小
spring.servlet.multipart.max-request-size=1GB
# 单文件大小
spring.servlet.multipart.max-file-size=1GB
# 文件达到多少磁盘写入
spring.servlet.multipart.file-size-threshold=100MB
# 直接存服务器的路径
spring.servlet.multipart.location=/home
SpringBoot对multipartResolver的自动装配: MultipartAutoConfiguration
直接贴代码,看下面,说几点:
1.multipartResolver的默认实现StandardServletMultipartResolver:
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)这个bean的名字,就是multipartResolver,是生成的StandardServletMultipartResolver,
2.CommonsMultipartResolver是默认不生成的
@ConditionalOnMissingBean({ MultipartConfigElement.class, CommonsMultipartResolver.class }),默认没CommonsMultipartResolver的bean才创建配置
3.spring.servlet.multipart是给StandardServletMultipartResolver用的
所以如果我就要用CommonsMultipartResolver生成bean,spring.servlet.multipart白配
/**
* {@link EnableAutoConfiguration Auto-configuration} for multi-part uploads. Adds a
* {@link StandardServletMultipartResolver} if none is present, and adds a
* {@link javax.servlet.MultipartConfigElement multipartConfigElement} if none is
* otherwise defined. The {@link ServletWebServerApplicationContext} will associate the
* {@link MultipartConfigElement} bean to any {@link Servlet} beans.
* <p>
* The {@link javax.servlet.MultipartConfigElement} is a Servlet API that's used to
* configure how the server handles file uploads.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
//"spring.servlet.multipart"配置的开启
@ConditionalOnProperty(prefix = "spring.servlet.multipart", name = "enabled", matchIfMissing = true)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartAutoConfiguration {
private final MultipartProperties multipartProperties;
//"spring.servlet.multipart"配置的引入
public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
this.multipartProperties = multipartProperties;
}
//没CommonsMultipartResolver才使用"spring.servlet.multipart"配置
@Bean
@ConditionalOnMissingBean({ MultipartConfigElement.class, CommonsMultipartResolver.class })
public MultipartConfigElement multipartConfigElement() {
return this.multipartProperties.createMultipartConfig();
}
//默认生成StandardServletMultipartResolver
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
}
自定义multipartResolver
如果不改spring.servlet.multipart前缀,SpringBoot还是会检查报错的,所以改一下
my:
servlet:
multipart:
maxUploadSize: 1073741824
maxInMemorySize: 104857600
@Data
@Configuration
@ConfigurationProperties(prefix = "my.servlet.multipart", ignoreUnknownFields = false)
public class MultipartAutoConfiguration {
private long maxUploadSize;
private int maxInMemorySize;
@Bean(name = "multipartResolver")
public CommonsMultipartResolver getCommonsMultipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(this.maxUploadSize);
multipartResolver.setMaxInMemorySize(this.maxInMemorySize);
return multipartResolver;
}
}