1.和之前一样创建Spring Boot项目,选择Web模块,XX模块等
2.可自己指定配置
3.自己编写业务代码
2.Spring Boot对静态资源的映射WebMvcAutoConfiguration.java中的addResourceHandlers方法添加资源映射
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjarsfavicon.ico
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
faviconRequestHandler()));
return mapping;
}
@Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
requestHandler
.setLocations(this.resourceProperties.getFaviconLocations());
return requestHandler;
}
}
this.resourceProperties.getFaviconLocations()也是在静态资源路径上找
List1)、所有 /webjarsfavicon.ico 都是在静态资源文件下找;getFaviconLocations() { List locations = new ArrayList ( this.staticLocations.length + 1); if (this.resourceLoader != null) { for (String location : this.staticLocations) { locations.add(this.resourceLoader.getResource(location)); } } locations.add(new ClassPathResource("/")); return Collections.unmodifiableList(locations); }
标题栏左侧的图标
二、模板引擎JSP、Velocity、Freemarker、Thymeleaf
模板引擎的思想:写一个模板,数据填充,通过模板引擎,输出一个带数据的完整页面等等
SpringBoot推荐的Thymeleaf;语法更简单,功能更强大;
1.Thymeleaf模板引擎Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSP,Velocity,FreeMaker等,它也可以轻易的与Spring MVC等Web框架进行集成 作为Web应用的模板引擎。与其它模板引擎相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用
Spring Boot推荐使用Thymeleaf、Freemarker等后现代的模板引擎技术;一但导入相关依赖,会自动配置ThymeleafAutoConfiguration、FreeMarkerAutoConfiguration。
1)引入thymeleaf;2)Thymeleaf使用org.springframework.boot spring-boot-starter-thymeleaf3.0.9.RELEASE 2.2.2
ThymeleafProperties.java文件
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
只要我们把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染;
使用:
1、html中导入thymeleaf的名称空间:作用:可使用语法提示
2、使用thymeleaf语法;
Title
Hello World
这是显示欢迎信息
Controller层,如下:
@RequestMapping("/hello")
public String success(Map map){
map.put("hello","你好");
return "hello";
}
3)语法规则
Thymeleaf官网:Thymeleaf
Thymeleaf官网Docs,可下载pdf文档。
1.th:text;改变当前元素里面的文本内容;
th:任意html属性;来替换原生属性的值
th:属性的优先级,从上到下依次递减
Order Feature Attributes
1 片段包含 th:insert
th:replace
2 遍历 th:each
3 条件判断 th:if
th:unless
th:switch
th:case
4 声明变量 th:object
th:with
5 任意属性修改 th:attr
th:attrprepend
th:attrappend
6 修改指定属性默认值 th:value
th:href
th:src
...
7 修改标签体内容 th:text //转义特殊字符
th:utext //不转义特殊字符
8 声明片段 th:fragment
9 片段移除 th:remove
2.表达式语法
Simple expressions: //表达式语法
Variable expressions: ${...} //:获取变量值;OGNL;
1)、获取对象的属性、调用方法
2)、使用内置的基本对象:
Selection Variable expressions: *{...}:选择表达式:和${}在功能上是一样;
Message expressions: #{...} :获取国际化内容
link URL expressions: @{...}:定义URL;
Fragment expressions: ~{...}:片段引用表达式
Literals //字面量
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations://文本操作
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations://数学运算
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Boolean operations://布尔运算
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality://比较运算
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators://条件运算(三元运算符)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens:
No-Operation: _
三、SpringMVC自动配置
官网介绍SpringMVC自动配置
Spring MVC auto-configuration
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.
Support for serving static resources, including support for WebJars (see below).//静态资源路径和webjars支持
Automatic registration of Converter, GenericConverter, Formatter beans.
Support for HttpMessageConverters (see below).
Automatic registration of MessageCodesResolver (see below).
Static index.html support.//静态首页访问
Custom Favicon support (see below).//favicon.ico图标
Automatic use of a ConfigurableWebBindingInitializer bean (see below).
If you want to keep Spring Boot MVC features, and you just want to add additional MVC
configuration (interceptors, formatters, view controllers etc.) you can add your own
@Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you
wish to provide custom instances of RequestMappingHandlerMapping,
RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a
WebMvcRegistrationsAdapter instance providing such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration
annotated with @EnableWebMvc.
1.SpringMVC自动配置
Ⅰ.自动配置了ViewResolver
SpringBoot对SpringMVC的默认配置:WebMvcAutoConfiguration.java
自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发/重定向))
WebMvcAutoConfiguration.java中的
ContentNegotiatingViewResolver:作用:组合所有的视图解析器的;
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(
beanFactory.getBean(ContentNegotiationManager.class));
// ContentNegotiatingViewResolver uses all the other view resolvers to locate
// a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
ContentNegotiatingViewResolver.java解析视图
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
List candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
if (this.useNotAcceptableStatusCode) {
if (logger.isDebugEnabled()) {
logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
}
return NOT_ACCEPTABLE_VIEW;
}
else {
logger.debug("No acceptable view found; returning null");
return null;
}
}
getCandidateViews
private ListgetCandidateViews(String viewName, Locale locale, List requestedMediaTypes) throws Exception { List candidateViews = new ArrayList (); for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { candidateViews.add(view); } for (MediaType requestedMediaType : requestedMediaTypes) { List extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType); for (String extension : extensions) { String viewNameWithExtension = viewName + '.' + extension; view = viewResolver.resolveViewName(viewNameWithExtension, locale); if (view != null) { candidateViews.add(view); } } } } if (!CollectionUtils.isEmpty(this.defaultViews)) { candidateViews.addAll(this.defaultViews); } return candidateViews; }
viewResolvers
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
implements ViewResolver, Ordered, InitializingBean {
......
private List viewResolvers;
.....
@Override
protected void initServletContext(ServletContext servletContext) {
Collection matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), ViewResolver.class).values();
if (this.viewResolvers == null) {
this.viewResolvers = new ArrayList(matchingBeans.size());
for (ViewResolver viewResolver : matchingBeans) {
if (this != viewResolver) {
this.viewResolvers.add(viewResolver);
}
}
}
else {
for (int i = 0; i < viewResolvers.size(); i++) {
if (matchingBeans.contains(viewResolvers.get(i))) {
continue;
}
String name = viewResolvers.get(i).getClass().getName() + i;
getApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolvers.get(i), name);
}
}
if (this.viewResolvers.isEmpty()) {
logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the " +
"'viewResolvers' property on the ContentNegotiatingViewResolver");
}
AnnotationAwareOrderComparator.sort(this.viewResolvers);
this.cnmFactoryBean.setServletContext(servletContext);
}
BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), ViewResolver.class).values();会把所有的ViewResolver视图解析器组合起来。
如何自己添加视图解析器:我们可以自己给容器中添加一个视图解析器;SpringBoot会自动的将其组合进来;
例子:
@SpringBootApplication
public class SpringBootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestApplication .class, args);
}
@Bean
public ViewResolver myViewReolver(){
return new MyViewResolver();
}
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
如何查看自己加的视图是否添加进去了呢?
在DispatcherServlet.java中doDispatch方法处打一个断点。因为所有请求一进来会先执行doDispatch方法。
启动Spring Boot项目,随便访问一个请求,查看DispatcherServlet对象中是否有自己添加的ViewResolver。
Ⅱ.Converter、FormatterConverter:转换器,页面输入值和后台类型之间的转换,类型转换使用Converter
Formatter :格式化器,日期,2018.2.18;
WebMvcAutoConfiguration.java中配置了日期的格式化器
@Bean @ConditionalOnProperty(prefix = "spring.mvc", name = "date-format") public FormatterdateFormatter() { return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件 }
可在application.properties文件中指定日期格式:spring.mvc.date-format=yyyy-MM-dd
WebMvcAutoConfiguration.java把格式化器等添加进容器中addFormatters
@Override
public void addFormatters(FormatterRegistry registry) {
for (Converter, ?> converter : getBeansOfType(Converter.class)) {
registry.addConverter(converter);
}
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
registry.addConverter(converter);
}
for (Formatter> formatter : getBeansOfType(Formatter.class)) {
registry.addFormatter(formatter);
}
}
private Collection getBeansOfType(Class type) {
return this.beanFactory.getBeansOfType(type).values();
}
自己添加的格式化器转换器,我们只需要放在容器中即可
Ⅲ.HttpMessageConverterHttpMessageConverter:SpringMVC用来转换Http请求和响应的;
WebMvcAutoConfiguration.java HttpMessageConverter
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
.........
// Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not
// on the classpath
@Configuration
@import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
......
private final HttpMessageConverters messageConverters;
......
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties,
WebMvcProperties mvcProperties, ListableBeanFactory beanFactory,
@Lazy HttpMessageConverters messageConverters,
ObjectProvider resourceHandlerRegistrationCustomizerProvider) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConverters = messageConverters;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider
.getIfAvailable();
}
@Override
public void configureMessageConverters(List> converters) {
converters.addAll(this.messageConverters.getConverters());
}
HttpMessageConverters 是从容器中确定;获取所有的HttpMessageConverter;
自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中 (@Bean,@Component)
Ⅳ.MessageCodesResolverMessageCodesResolver:定义错误代码生成规则
WebMvcAutoConfiguration.java MessageCodesResolver
@Override
public MessageCodesResolver getMessageCodesResolver() {
if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
resolver.setMessageCodeFormatter(
this.mvcProperties.getMessageCodesResolverFormat());
return resolver;
}
return null;
}
getMessageCodesResolverFormat()
public DefaultMessageCodesResolver.Format getMessageCodesResolverFormat() {
return this.messageCodesResolverFormat;
}
this.messageCodesResolverFormat
private DefaultMessageCodesResolver.Format messageCodesResolverFormat;
Format--->error code
public enum Format implements MessageCodeFormatter {
PREFIX_ERROR_CODE {
@Override
public String format(String errorCode, String objectName, String field) {
return toDelimitedString(errorCode, objectName, field);
}
},
.......
Ⅴ.ConfigurableWebBindingInitializer
ConfigurableWebBindingInitializer:初始化WebDataBinder;请求数据绑定JavaBean;
WebMvcAutoConfiguration.java ConfigurableWebBindingInitializer
@Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
try {
return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
}
catch (NoSuchBeanDefinitionException ex) {
return super.getConfigurableWebBindingInitializer();
}
}
this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);从容器中拿ConfigurableWebBindingInitializer
我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器)
super.getConfigurableWebBindingInitializer()
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(mvcConversionService());
initializer.setValidator(mvcValidator());
initializer.setMessageCodesResolver(getMessageCodesResolver());
return initializer;
}
ConfigurableWebBindingInitializer
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
if (this.directFieldAccess) {
binder.initDirectFieldAccess();
}
if (this.messageCodesResolver != null) {
binder.setMessageCodesResolver(this.messageCodesResolver);
}
if (this.bindingErrorProcessor != null) {
binder.setBindingErrorProcessor(this.bindingErrorProcessor);
}
if (this.validator != null && binder.getTarget() != null &&
this.validator.supports(binder.getTarget().getClass())) {
binder.setValidator(this.validator);
}
if (this.conversionService != null) {
binder.setConversionService(this.conversionService);
}
if (this.propertyEditorRegistrars != null) {
for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
propertyEditorRegistrar.registerCustomEditors(binder);
}
}
}
初始化WebDataBinder;请求数据绑定JavaBean;
不止以上这些自动配置
想了解更多auto-configuration :org.springframework.boot.autoconfigure.web:web的所有自动场景;
2.扩展SpringMVC① 编写一个配置类(@Configuration),
②是WebMvcConfigurerAdapter类型;
③不能标注@EnableWebMvc;
既保留了SpringBoot所有的自动配置,也能用我们扩展的配置;
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /hello1 请求来到 hello
registry.addViewController("/hello1").setViewName("hello");
}
}
原理:
1、WebMvcAutoConfiguration是SpringMVC的自动配置类
2、WebMvcAutoConfiguration.java
@import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
在做其他自动配置时会导入;@import(EnableWebMvcConfiguration.class)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
从容器中获取所有的WebMvcConfigurer放到configurers中
@Autowired(required = false)
public void setConfigurers(List configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
....
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
.....
this.configurers.addViewControllers(registry);//一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
}
3、容器中所有的WebMvcConfigurer都会一起起作用;
4、我们的配置类也会被调用;
效果:SpringMVC的自动配置和我们的扩展配置都会起作用;
3.全面接管SpringMVC,只要在配置类添加@EnableWebMvc即可SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了
我们需要在配置类中添加@EnableWebMvc即可;
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /hello1 请求来到 hello
registry.addViewController("/hello1").setViewName("hello");
}
}
证明效果:
不加@EnableWebMvc,启动项目,会在控制台打印出 filter: 'hiddenHttpMethodFilter'等log
加@EnableWebMvc,则不输出该log。
2021-11-06 21:19:17.243 INFO 5836 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
因为WebMvcAutoConfiguration.java 中定义hiddenHttpMethodFilter过滤器
public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = "";
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
...
原理:为什么@EnableWebMvc自动配置就失效了;
1、@EnableWebMvc的核心
@import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
2、DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3、WebMvcAutoConfiguration
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
4、@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;导致WebMvcAutoConfiguration 判断条件使自动配置失效。
5、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能
4.如何修改SpringBoot的默认配置模式:
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如 果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默 认的组合起来;
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置
Spring Boot入门+深入(一):Spring Boot入门+深入(一)_杀神lwz的博客-CSDN博客
Spring Boot入门+深入(五):Spring Boot入门+深入(五)_杀神lwz的博客-CSDN博客



