這幾天在使用springboot時,controller層接受前端傳入的數據爲null,而在發送請求時也是有數據的,這就讓我很疑惑,於是在查看了一下源碼,發現了問題所在。
1. 我們都知道,在springboot啓動完成之後,會加載很多的bean進入容器,怎麼加載的請在網上自行搜索,其中就有這麼一個配置類DispatcherServletAutoConfiguration.java,看源碼:
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
/*
* The bean name for a DispatcherServlet that will be mapped to the root URL "/"
*/
public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
/*
* The bean name for a ServletRegistrationBean for the DispatcherServlet "/"
*/
public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
@Configuration
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {
private final WebMvcProperties webMvcProperties;
public DispatcherServletConfiguration(WebMvcProperties webMvcProperties) {
this.webMvcProperties = webMvcProperties;
}
@Bean //就是這個bean啦
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
}
}
我們會發現DispatcherServletAutoConfiguration.java類中DispatcherServletConfiguration內部類中會向容器中導入一個MultipartResolver類型的bean,要想導入這個bean是有前提的,容器中需要有MultipartResolver.class的類,而且需要當容器中沒有這個名字的bean,name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME,而這個name是這樣的:
package org.springframework.web.servlet;
public class DispatcherServlet extends org.springframework.web.servlet.FrameworkServlet {
public static final java.lang.String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
這樣我們就知道了,當我們容器中有MultipartResolver.class這個類,卻沒有multipartResolver名字的bean,這時springboot認爲我們的命名不規範,就會容器中註冊一個multipartResolver名字的,類型爲MultipartResolver的bean。
2. 我們查看另一個配置類MultipartAutoConfiguration.java,
@Configuration
@ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class,
MultipartConfigElement.class })
@ConditionalOnProperty(prefix = "spring.http.multipart", name = "enabled",
matchIfMissing = true)
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartAutoConfiguration {
private final MultipartProperties multipartProperties;
public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
this.multipartProperties = multipartProperties;
}
@Bean
@ConditionalOnMissingBean({ MultipartConfigElement.class,
CommonsMultipartResolver.class })
public MultipartConfigElement multipartConfigElement() {
return this.multipartProperties.createMultipartConfig();
}
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
}
它主要往容器中添加兩個bean,在添加multipartConfigElement時會判斷容器中是否缺少CommonsMultipartResolver和MultipartConfigElement類型的bean,如果缺少,那麼就multipartConfigElement加入容器中。
第二個bean是當缺少MultipartResolver類型的bean時,加入到容器。
當我們知道這些就可以解決爲啥controller傳入的爲空,我自己寫的MultipartResolver是這樣定義的:
//顯示聲明CommonsMultipartResolver爲mutipartResolver
@Bean(name = "multipartResolver")
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("UTF-8");
resolver.setMaxUploadSize(50 * 1024 * 1024);//上傳文件大小 50M 50*1024*1024
return resolver;
}
這樣定義我們來分析一下,首先容器會將在我們自己定義的bean到容器中,然後判斷前面的情況,在DispatcherServletAutoConfiguration類中的bean不會被加入到容器,爲什麼?因爲我們自己定義的bean已經叫multipartResolver了,所以不會加入到容器。
再看MultipartAutoConfiguration,multipartConfigElement會被加入到容器,因爲沒有CommonsMultipartResolver類型的bean,我自己寫的向上轉型了,StandardServletMultipartResolver 類型bean不會被加入到容器,這時容器有兩個bean,而且我自己定義的bean是MultipartResolver ,這時就會出錯了。
出錯原因是我們定義的MultipartResolver要明確的指出是哪個類的,不應該是MultipartResolver這個接口類型,改成
//顯示聲明CommonsMultipartResolver爲mutipartResolver
@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("UTF-8");
resolver.setMaxUploadSize(50 * 1024 * 1024);//上傳文件大小 50M 50*1024*1024
return resolver;
}
就可以了,這時在思考一下,會發現springboot只會將我們的multipartResolver加入到容器,multipartConfigElement則不會加入到容器。