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、简单功能分析

      image.png

      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 + 静态资源名 = 静态资源文件下找

  • 为了让拦截时能区分出静态资源和动态资源,所以规定静态资源前面加个前缀,拦截器在看到指定前缀时就放行,从而达到动态静态分开的目的。

image.png

3、改变默认的静态资源路径

spring:
web:
resources:
static-locations: [classpath:/staticpng/]
如果我们希望以后所有的静态资源都放在staticpng文件夹下
在application.yml中添加static-locations: [classpath:/staticpng/]
image.png

4、webjar

自动映射 /webjars/**
https://www.webjars.org/


org.webjars
jquery
3.5.1

访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径
image.png

2.2、欢迎页支持

  • 静态资源路径下 index.html
    • 可以配置静态资源路径
    • 但是不可以配置静态资源访问前缀,否则导致index.html不能被默认访问

spring:
# mvc:
# static-path-pattern: /res/**

web:
resources:
static-locations: [classpath:/staticpng/]
image.png

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, ObjectProvider messageConvertersProvider,
    ObjectProvider resourceHandlerRegistrationCustomizerProvider,
    ObjectProvider dispatcherServletPath,
    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 {

  1. private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",<br /> "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
  2. /**<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 welcomePage, String staticPathPattern) {
//要用欢迎页功能,必须是/ 就是说我们的修改默认静态资源路径不允许
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 {

  1. @RequestMapping(value = "/user",method = RequestMethod.GET)<br /> public String getUser(){<br /> return "GET-张三";<br /> }
  2. @RequestMapping(value = "/user",method = RequestMethod.POST)<br /> public String saveUser(){<br /> return "POST-张三";<br /> }
  3. @RequestMapping(value = "/user",method = RequestMethod.PUT)<br /> public String putUser(){<br /> return "PUT-张三";<br /> }
  4. @RequestMapping(value = "/user",method = RequestMethod.DELETE)<br /> public String deleteUser(){<br /> return "DELETE-张三";<br /> }<br />}<br />@Configuration(proxyBeanMethods = false)<br />public class WebConfig {
  5. @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的。**

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、视图解析与模板引擎

image.png