SpringBoot定制化开发
1.定制化方式
- 开启默认组件。可以通过修改配置文件
application.properties
的方式 - 替换默认组件。可以编写自定义的配置类
xxxAutoConfiguration + @Bean
,以此来增加、替换容器中默认组件,可以达到替换组件的目的,底层更多是借助@ConditionalOnMissingBean
注解,优先使用自定义的,否则使用默认的 重写 WebMvcConfigurer 接口
+@Component
,可定制化Web功能**(推荐使用)**重写 WebMvcConfigurer 接口
+@EnableWebMvc
可以全面接管Web,但这样会导致默认的规则全部失效,需要全部重新配置
2.WebMvcConfigurer 接口
下面介绍该接口,并对常用方法解析
public interface WebMvcConfigurer {
// 配置路由匹配规则
default void configurePathMatch(PathMatchConfigurer configurer) {}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
// 默认静态资源处理器
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
default void addFormatters(FormatterRegistry registry) {}
// 自定义拦截器配置
default void addInterceptors(InterceptorRegistry registry) {}
// 添加静态资源访问
default void addResourceHandlers(ResourceHandlerRegistry registry) {}
default void addCorsMappings(CorsRegistry registry) {}
// 添加视图解析器(添加一个页面跳转)
default void addViewControllers(ViewControllerRegistry registry) {}
default void configureViewResolvers(ViewResolverRegistry registry) {}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
<1> addInterceptors()
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new FirstInterceptor())
.addPathPatterns("/**") // 设置拦截路径
.excludePathPatterns("/index5"); // 设置拦截排除路径
}
};
}
<2> addResourceHandlers()
添加处理程序以从 Web 应用程序根目录、类路径等的特定位置提供静态资源,例如图像、js 和 css 文件。
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// addResoureHandler:指的是对外暴露的访问路径
// addResourceLocations:指的是内部文件放置的目录
registry.addResourceHandler("/**").addResourceLocations("classpath:/h3c/");
}
};
}
<3> addViewControllers()
配置视图跳转控制
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/toLogin").setViewName("index2");
}
};
}
<4> configureViewResolvers()
配置视图解析器以将从控制器返回的基于字符串的视图名称转换为具体的 {@link org.springframework.web.servlet.View} 实现以执行渲染
/**
* Configure view resolvers to translate String-based view names returned from
* controllers into concrete {@link org.springframework.web.servlet.View}
* implementations to perform rendering with.
* @since 4.1
*/
default void configureViewResolvers(ViewResolverRegistry registry) {
}
配置实例
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
registry.viewResolver(resolver);
}
};
}
3.@EnableWebMvc 会导致默认规则失效
当我们添加配置类,只实现了WebMvcConfigurer
接口,这样可以向容器中添加自定义配置,但是如果使用了@EnableWebMvc
会导致默认配置全部失效,为何呢?
@EnableWebMvc
添加以后会向容器中注入一个DelegatingWebMvcConfiguration.class
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class) // 引入类
public @interface EnableWebMvc {}
注入的类中有两点需要关注:
- 该类继承了
WebMvcConfigurationSupport
- 该类中的
setConfigurers()
会将所有的WebMvcConfigurer
全部存入,这代表的意思是存在多个自定义配置类,系统会把配置合并到一起
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { // 注意继承了该类,下面会用到
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
// 这里参数是个集合,代表当存在多个自定义配置,会把配置合并到一起
this.configurers.addWebMvcConfigurers(configurers);
}
}
// 省略部分代码...
}
而我们的自动配置类WebMvcAutoConfiguration
,在其条件中有很重要的一条@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
,而@EnableWebMvc
导入的类正好继承了WebMvcConfigurationSupport
,所以如果我们通过@EnableWebMvc + WebMvcConfigurer
来自定义配置的话,自动配置的东西就会全部失效,需要我们全部重写
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) // 注意看这里,当WebMvcConfigurationSupport不存在
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {}
结论:如果我们定义接口实现WebMvcConfigurer
,那么系统会把自定义的配置和默认配置合并一起,如果使用了@EnableWebMvc
,那么配置全部失效,需要重写,那么相比之下,显而易见应该用哪个