SpringBoot2学习笔记
四、Web开发
4.1)SpringMVC自动配置概述
我们都无需自定义配置)
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 页支持
Custom Favicon
support (covered later in this document).
-
自定义
Favicon
Automatic use of a ConfigurableWebBindingInitializer
bean (covered later in this document).
-
自动使用
ConfigurableWebBindingInitializer
,(DataBinder负责将请求数据绑定到JavaBean上)
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own
@Configuration
class of typeWebMvcConfigurer
but without@EnableWebMvc
.不用@EnableWebMvc注解。使用
**@Configuration**
+**WebMvcConfigurer**
自定义规则If you want to provide custom instances of
RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
, orExceptionHandlerExceptionResolver
, and still keep the Spring Boot MVC customizations, you can declare a bean of typeWebMvcRegistrations
and use it to provide custom instances of those components.声明
**WebMvcRegistrations**
改变默认底层组件If you want to take complete control of Spring MVC, you can add your own
@Configuration
annotated with@EnableWebMvc
, or alternatively add your own@Configuration
-annotatedDelegatingWebMvcConfiguration
as described in the Javadoc of@EnableWebMvc
.使用
**@EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration 全面接管SpringMVC**
4.2)简单功能分析
4.2.1)静态资源访问
4.2.1.1)静态资源目录
只要静态资源放在类路径下: called /static
(or /public
or /resources
or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
示例:工程中新建相应的文件夹,目录如下图
浏览器访问:
http://localhost:8080/resources.jpg,图片如下:
http://localhost:8080/public.gifhttp://localhost:8080/static.png,图片如下:
原理: 静态映射/**,拦截所以请求;请求进来,先去找Controller看能不能处理;不能处理的所有请求又都交给静态资源处理器;静态资源也找不到则响应404页面
新建 HelloController.java,代码如下:
@RestController
public class HelloController {
@RequestMapping("/metainf.jpg")
public String hello(){
return "aaaa";
}
}
浏览器访问:http://localhost:8080/metainf.jpg,图片如下:
改变默认的静态资源路径
4.2.2)静态资源访问前缀
默认无前缀,application.yaml,代码如下:
spring:
mvc:
static-path-pattern: /res/**
当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
浏览器访问:http://localhost:8080/resources.jpg,页面报错,访问:http://localhost:8080/res/resources.jpg,页面可以正常访问,如下图:
4.2.2.1)改变默认的静态资源路径
修改配置文件application.yaml,代码如下:
spring:
mvc:
# 静态资源访问默认无前缀
static-path-pattern: /res/**
resources:
# 改变默认的静态资源路径
static-locations: [classpath:/abc/]
浏览器访问:http://localhost:8080/resources.jpg,页面报错,访问:http://localhost:8080/res/abc.jpg,页面可以正常访问,如下图:
4.2.3)欢迎页支持
-
静态资源路径下 index.html
可以配置静态资源路径
但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
清空配置文件application.yaml,不使用额外配置【配置访问前缀会导致welcome page功能失效】,在resource目录下新建首页index.html,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>SpringBoot,欢迎您</h1>
<br>
</body>
</html>
浏览器访问默认地址:http://localhost:8080/,页面如下图:
4.2.4)自定义 Favicon
自定义网页图标,favicon.ico 放在静态资源目录下即可,放到static目录下,浏览器访问默认地址:http://localhost:8080/,页面如下图:【配置访问前缀会导致自定义 Favicon功能失效】
4.2.5)静态资源配置原理
-
SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
-
SpringMVC功能的自动配置类 WebMvcAutoConfiguration,通过它实现资源配置,源码如下:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = "";
private static final String[] SERVLET_LOCATIONS = new String[]{"/"};
public WebMvcAutoConfiguration() {
}
...
}
4.2.5.1)配置类只有一个有参构造器
给容器中配置内容:WebMvcAutoConfigurationAdapter方法,配置文件的相关属性和xxx进行了绑定。WebMvcProperties==spring.mvc、ResourceProperties==spring.resources,源码如下:
@ConfigurationProperties(
prefix = "spring.mvc"
)
public class WebMvcProperties {
private org.springframework.validation.DefaultMessageCodesResolver.Format messageCodesResolverFormat;
...
}
——————————————————————————————————————————————————————————————————
@ConfigurationProperties(
prefix = "spring.resources",
ignoreUnknownFields = false
)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private String[] staticLocations;
private boolean addMappings;
private final ResourceProperties.Chain chain;
private final ResourceProperties.Cache cache;
...
}
有参构造器所有参数的值都会从容器中确定:
ResourceProperties resourceProperties:获取和spring.resources绑定的所有的值的对象
WebMvcProperties mvcProperties :获取和spring.mvc绑定的所有的值的对象
ListableBeanFactory beanFactory :Spring的beanFactory
HttpMessageConverters: 找到所有的HttpMessageConverters
ResourceHandlerRegistrationCustomizer :找到资源处理器的自定义器
ServletRegistrationBean : 给应用注册Servlet、Filter....
WebMvcAutoConfigurationAdapter方法,源码如下:
@Configuration(
proxyBeanMethods = false
)
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final ResourceProperties resourceProperties;
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
private final ObjectProvider<DispatcherServletPath> dispatcherServletPath;
private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}
...
}
在配置文件application.yaml中可以设置禁用静态资源,代码如下:
spring:
mvc:
static-path-pattern: /res/**
resources:
# 禁用所有静态资源规则
add-mappings: false
4.2.5.2)欢迎页的处理规则
HandlerMapping:处理器映射。保存了每一个Handler能处理哪些请求。
WelcomePageHandlerMapping,源码如下
@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<Resource> 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");
}
}