1、SpringMVC自动配置概览
官方文档说明
[springmvc] https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.servlet springmvc
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
The auto-configuration adds the following features on top of Spring’s defaults:
- Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
- 内容协商视图解析器和BeanName视图解析器
- Support for serving static resources, including support for WebJars (covered later in this document).
- 静态资源(包括webjars)
- Automatic registration of Converter, GenericConverter, and Formatter beans.
- 自动注册 Converter,GenericConverter,Formatter
- Support for HttpMessageConverters (covered later in this document).
- 支持 HttpMessageConverters (后来我们配合内容协商理解原理)
- Automatic registration of MessageCodesResolver (covered later in this document).
- 自动注册 MessageCodesResolver (国际化用)
- Static index.html support.
- 静态index.html 页支持
Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
- 自动使用 ConfigurableWebBindingInitializer ,(DataBinder负责将请求数据绑定到JavaBean上)
2、简单功能分析
2.1、静态资源访问
1、静态资源目录
只要静态资源放在类路径下: 系统默认/static (or /public or /resources or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
原理: 静态映射/。
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面
spring:
mvc:
static-path-pattern: /res/
resources:
static-locations: [classpath:/haha/]2、静态资源访问前缀
spring:
mvc:
static-path-pattern: /res/**
访问路径时要加前缀进行访问资源,当前项目 + static-path-pattern + 静态资源名 = 静态资源文件下找- 自动使用 ConfigurableWebBindingInitializer ,(DataBinder负责将请求数据绑定到JavaBean上)
为了让拦截时能区分出静态资源和动态资源,所以规定静态资源前面加个前缀,拦截器在看到指定前缀时就放行,从而达到动态静态分开的目的。
3、改变默认的静态资源路径
spring:
web:
resources:
static-locations: [classpath:/staticpng/]
如果我们希望以后所有的静态资源都放在staticpng文件夹下
在application.yml中添加static-locations: [classpath:/staticpng/]
4、webjar
自动映射 /webjars/**
https://www.webjars.org/
访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径
2.2、欢迎页支持
- 静态资源路径下 index.html
- 可以配置静态资源路径
- 但是不可以配置静态资源访问前缀,否则导致index.html不能被默认访问
spring:
# mvc:
# static-path-pattern: /res/**
web:
resources:
static-locations: [classpath:/staticpng/]
2.3、自定义Favicon
favicon.ico 放在静态资源目录下即可
但是修改默认的静态资源路径会导致功能失效
#spring:
## mvc:
## static-path-pattern: /res/**
#
# web:
# resources:
# static-locations: [classpath:/staticpng/] 这个修改会失效
2.4、静态资源配置原理
- SpringBoot默认开启XXXAutoConfiguration类(自动配置类)
- SpringMVC功能的自动配置类WebAutoConfiguration,默认生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}
给容器中默认配置
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
- 配置文件的相关属性和xxx进行了绑定。WebMvcProperties == ==spring.mvc、==
- ==ResourceProperties== == spring.resources
1. 配置类中只有一个有参构造器
//有参构造器所有参数的值都会从容器中确定
//ResourceProperties resourceProperties;获取和spring.resources绑定的所有的值的对象
//WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象
//ListableBeanFactory beanFactory Spring的beanFactory
//HttpMessageConverters 找到所有的HttpMessageConverters
//ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。=========
//DispatcherServletPath
//ServletRegistrationBean 给应用注册Servlet、Filter….
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory, ObjectProvidermessageConvertersProvider,
ObjectProviderresourceHandlerRegistrationCustomizerProvider,
ObjectProviderdispatcherServletPath,
ObjectProvider> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}2. 资源处理的默认规则
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// isAddMappings默认为true
if (!this.resourceProperties.isAddMappings()) {
logger.debug(“Default resource handling disabled”);
return;
}
// 缓存时间
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
// 静态资源查找
if (!registry.hasMappingForPattern(“/webjars/“)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(“/webjars/“)
.addResourceLocations(“classpath:/META-INF/resources/webjars/“)
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
// /** 开始查抄
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
// 处理映射规则
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
spring:
# mvc:
# static-path-pattern: /res/**
resources:
add-mappings: false 禁用所有静态资源规则
# 当禁用所有静态资源规则的时候,自动配置不生效,访问不到静态资源
@ConfigurationProperties(prefix = “spring.resources”, ignoreUnknownFields = false)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",<br /> "classpath:/resources/", "classpath:/static/", "classpath:/public/" };/**<br /> * Locations of static resources. Defaults to classpath:[/META-INF/resources/,<br /> * /resources/, /static/, /public/].<br /> */<br /> private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
3. 欢迎页的处理规则
// HandlerMapping:处理器映射。保存了每一个Handler能处理哪些请求。
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
ApplicationContext applicationContext, Optional
//要用欢迎页功能,必须是/ 就是说我们的修改默认静态资源路径不允许
if (welcomePage.isPresent() && “/“.equals(staticPathPattern)) {
logger.info(“Adding welcome page: “ + welcomePage.get());
setRootViewName(“forward:index.html”);
}
else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
// 调用Controller /index
logger.info(“Adding welcome page template: index”);
setRootViewName(“index”);
}
}
3、请求参数处理
3.1、请求映射
1. rest使用及原理
- @xxxMapping
- Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
- 以前:**/getUser获取用户/deleteUser删除用户/editUser修改用户/saveUser保存用户
- 现在: /userGET-获取用户DELETE-删除用户PUT-修改用户POST-保存用户
- 核心Filter;HiddenHttpMethodFilter
- 用法: 表单method=post,隐藏域 _method=put
- SpringBoot中手动开启
- 扩展:如何把_method 这个名字换成我们自己喜欢的。
@RestController
public class HelloController {
@RequestMapping(value = "/user",method = RequestMethod.GET)<br /> public String getUser(){<br /> return "GET-张三";<br /> }@RequestMapping(value = "/user",method = RequestMethod.POST)<br /> public String saveUser(){<br /> return "POST-张三";<br /> }@RequestMapping(value = "/user",method = RequestMethod.PUT)<br /> public String putUser(){<br /> return "PUT-张三";<br /> }@RequestMapping(value = "/user",method = RequestMethod.DELETE)<br /> public String deleteUser(){<br /> return "DELETE-张三";<br /> }<br />}<br />@Configuration(proxyBeanMethods = false)<br />public class WebConfig {@Bean<br /> public HiddenHttpMethodFilter hiddenHttpMethodFilter(){<br /> HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();<br /> methodFilter.setMethodParam("_m");<br /> return methodFilter;<br /> }<br />}<br />Rest原理(表单提交要使用REST的时候)
- 表单提交会带上_method=PUT
- 请求过来被HiddenHttpMethodFilter拦截
- 请求是否正常,并且是POST
- 获取到_method的值。
- 兼容以下请求;PUT.DELETE.PATCH
- 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
- 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用**requesWrapper的。**
- 请求是否正常,并且是POST
Rest使用客户端工具,
- 如PostMan直接发送Put、delete等方式请求,无需Filter。
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能 默认开启
2. 请求映射原理
3.2、普通参数与基本注解
3.3、POJO封装过程
3.4、参数处理原则
4、数据响应与内容协商
4.1、响应JSON
4.2、内容协商
5、视图解析与模板引擎

