学习springmvc和springboot的自动配置我们必须对springmvc的组件足够了解,起码知道怎么用。Springmvc的组件基本都被springboot来做了自动的配置。
一、springboot的自动解管理
中央转发器(DispatcherServlet)
控制器
视图解析器
静态资源访问
消息转换器
格式化
静态资源管理
1.中央转换器
以前需要配置的xml现在无需配置
中央转发器被springboot自动接管,不再需要我们在web.xml中配置,我们现在的项目也不是web项目,也不存在web.xml,
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
2.控制器
控制器Controller在springboot的注解扫描范围内自动管理。
扫描的过程,为什么能被扫描到?
springboot里面有一个注解:@SpringBootApplication,这个注解的底层注解替我完成了一些事情:只要保证控制器所在的位置和启动类在同包或其子包下加上扫描注解就能被扫描到,为什么,因为@SpringBootApplication里面有一个注解@ComponentScan,但是这个注解只能达到扫描的作用,得提前告诉这个注解扫描谁,谁来告诉他,@ComponentScan里面有一个excludeFilters,过滤器,去排查我应该扫描哪些包,底层通过反射的方式拿到启动类所在的包,那么就会把启动类所在包及其子包下的所有东西扫描到,替换掉了原始方式的spring在配置文件里配置ComponentScan指定路径的方式
3.视图解析器自动管理
视图解析器原来也是在springmvc的配置文件里配置的:
<bean id="de" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"></property><property name="suffix" value="*.jsp"></property>
</bean>
源码:
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));resolver.setOrder(Integer.MIN_VALUE);return resolver;
}
靠它来形成的视图解析器,视图解析器的前缀后缀来源于thymeleaf的模板引擎:
这里配置的前缀后缀
@ConfigurationProperties(prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {private static final Charset DEFAULT_ENCODING;public static final String DEFAULT_PREFIX = "classpath:/templates/";public static final String DEFAULT_SUFFIX = ".html";private boolean checkTemplate = true;private boolean checkTemplateLocation = true;private String prefix = "classpath:/templates/";private String suffix = ".html";private String mode = "HTML";private Charset encoding;private boolean cache;private Integer templateResolverOrder;private String[] viewNames;private String[] excludedViewNames;private boolean enableSpringElCompiler;private boolean renderHiddenMarkersBeforeCheckboxes;private boolean enabled;private final Servlet servlet;private final Reactive reactive;
做文件上传的时候也会发现multipartResolver是自动被配置好的页面:
文件上传大小可以通过配置来修改
4.静态资源访问
springboot会默认将以下路径作为静态资源的目录
"classpath:/META‐INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":当前项目的根路径
5.消息转换和格式化
(1)Springboot自动配置了消息转换器
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {this.messageConvertersProvider.ifAvailable((customConverters) -> {converters.addAll(customConverters.getConverters());});
}
打个断点:
也就是说消息转换器有10个
(2)格式化转换器的自动注册
public void addFormatters(FormatterRegistry registry) {ApplicationConversionService.addBeans(registry, this.beanFactory);
}
可以在配置文件里修改时间类型
6.欢迎页面的自动配置
Springboot自动指定resources下的index.html
二、.springboot扩展springmvc
在实际开发中,springboot提供了很多自动配置的功能,简化了很多配置和开发工作,但它并非完全自动化,很多业务需要自己扩展,springboot提供了接口
1.通过实现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) {}@Nullabledefault Validator getValidator() {return null;}@Nullabledefault MessageCodesResolver getMessageCodesResolver() {return null;}
}
2.在容器中注册视图控制器(请求转发)
创建一个MyMVCCofnig实现WebMvcConfigurer接口,实现一下addViewControllers方法,我们完成通过/tx访问,转发到hei.html的工作
MyMVCCofnig
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MyMVCCofnig implements WebMvcConfigurer {//视图控制器(请求转发)@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/tx").setViewName("hei");}
}
hei.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
hello
</body>
</html>
运行
3.注册格式化器
用来可以对请求过来的日期格式化的字符串来做定制化,通过application.properties配置也可以办到。
//注册格式化器
@Override
public void addFormatters(FormatterRegistry registry) {registry.addFormatter(new Formatter<Date>() {@Overridepublic String print(Date date, Locale locale) {return null;}@Overridepublic Date parse(String s, Locale locale) throws ParseException {return new SimpleDateFormat("yyyy-MM-dd").parse(s);}});
}
4.消息转换器扩展fastjson
在pom文件中导入fastjson
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version>
</dependency>
配置消息转换器,添加fastjson
//配置消息转换器,添加fastjson
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {FastJsonHttpMessageConverter fc = new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);fc.setFastJsonConfig(fastJsonConfig);converters.add(fc);
}
在实体类上可以继续控制
public class User {private String username;private String password;private int age;private int score;private int gender;@JSONField(format = "yyyy-MM-dd")private Date date;
5.拦截器注册
以前是要先写拦截器类,再把拦截器配置到springmvc的配置文件里,现在不用了:
(1)创建拦截器
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("前置拦截");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("后置拦截");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("最终拦截");}
}
(2)拦截器注册
//拦截器注册
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/hello2");
}