SpringBoot学习笔记(六)SpringBoot_Web开
一、Thymeleaf模板
(一)简介
SpringBoot项目是jar包形式,内嵌Tomcat,故不支持jsp
静态的html太麻烦
- 故SpringBoot推荐使用模板引擎(JSP,Velocity,Freemarker,Thymeleaf......)
- 不同模板引擎之间的原理一样,但语法有差异
-
SpringBoot推荐使用Thymeleaf(语法更简单,功能更强大)
原理图.png
(二)引入Thymeleaf
pom.xml
//切换版本
<properties>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!--布局功能的支持程序thymeleaf3主程序layout2以上版本-->
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
.......
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
导入一些适配包时,一定要参考官方文档,避免出错
(三)Thymeleaf语法
官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html
语法教程::https://blog.csdn.net/u014042066/article/details/75614906
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";
........
}
即只要我们把HTML页面放在 classpath:/templates/,Thymeleaf就能自动渲染
success.html
<!DOCTYPE html>
<!--导入Thymeleaf名称空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>成功!</h1>
<!--th:text是设置文本内容-->
<div th:text="${Hello}"></div>
</body>
</html>
@Controller
public class HelloController {
//classpath:/templates/success.html
//查出一些数据,在页面展示
@RequestMapping("/success")
public String success(Map<String,Object> map) {
map.put("Hello","你好!");
return "success";
}
}
image.png
浏览器访问即可
image.png
-
th:任意html属性------替换原生属性
image.png - 能写哪些表达式
Simple expressions:
Variable Expressions: ${...}
Selection Variable Expressions: *{...}
Message Expressions: #{...}
Link URL Expressions: @{...}
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: _
All these features can be combined and nested:
'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))
ariable Expressions: ${...}
1.获取对象的调用属性,调用方法
2.使用内置的基本对象
#ctx: the context object.
#vars: the context variables.
#locale: the context locale.
#request: (only in Web Contexts) the HttpServletRequest object.
#response: (only in Web Contexts) the HttpServletResponse object.
#session: (only in Web Contexts) the HttpSession object.
#servletContext: (only in Web Contexts) the ServletContext object.
So we can do this:
Established locale country: <span th:text="${#locale.country}">US</span>.
3.使用内置的一些工具对象
#execInfo: information about the template being processed.
#messages: methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris: methods for escaping parts of URLs/URIs
#conversions: methods for executing the configured conversion service (if any).
#dates: methods for java.util.Date objects: formatting, component extraction, etc.
#calendars: analogous to #dates, but for java.util.Calendar objects.
#numbers: methods for formatting numeric objects.
#strings: methods for String objects: contains, startsWith, prepending/appending, etc.
#objects: methods for objects in general.
#bools: methods for boolean evaluation.
#arrays: methods for arrays.
#lists: methods for lists.
#sets: methods for sets.
#maps: methods for maps.
#aggregates: methods for creating aggregates on arrays or collections.
#ids: methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
Selection Variable Expressions: *{...}
用法跟${...}一致,但以下一点值得注意:
<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
跟下面的写法效果相同
<div>
<p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
</div>
这种时候$跟*可以混合使用
Message Expressions: #{...}
获取国际化内容
Link URL Expressions: @{...}
定义url
@{/order/process(execId=${execId},execType='FAST')}
Fragment Expressions: ~{...}
片段引用表达式
<div th:insert="~{commons :: main}">...</div>
二、SpringMVC自动配置原理
Spring MVC Auto-configuration
Spring Boot 自动配置好了SpringMVC
以下是SpringBoot对SpringMVC的默认
- Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans.
自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View)视图对象决定如何渲染(转发?重定向?))
ContentNegotiatingViewResolver :组合所有的视图解析器的
如何定制:我们可以自己给容器添加一个视图解析器,让其自动组合进来 - Support for serving static resources, including support for WebJars (covered later in this document)).
静态资源文件夹路径,webjars - 自动注册了
Converter
,GenericConverter
, andFormatter
beans.
Converter(转换器):类型转换使用,一般页面提交的都是String类型的数据,需要按需转为Boolean,Integer等类型
Formatter (格式化器):按一定的格式转换为某一类型。如2017-07-03转为Date,2017/07/03转为Data
定制:放在容器中即可 - Support for
HttpMessageConverters
(covered later in this document).
HttpMessageConverters:SpringMVC用来转换http请求和响应
HttpMessageConverters是从容器中确定的,获取所有的HttpMessageConverters
定制:将自己的组件注册到容器中(@Bean,@Component) - Automatic registration of
MessageCodesResolver
(covered later in this document).
定义错误代码生成规则 - Static
index.html
support.静态首页访问 - Custom
Favicon
support (covered later in this document). - Automatic use of a
ConfigurableWebBindingInitializer
bean (covered later in this document).
我们可以配置一个ConfigurableWebBindingInitializer,来替换默认的
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration
class of type WebMvcConfigurer
but without @EnableWebMvc
. If you wish to provide custom instances of RequestMappingHandlerMapping
, RequestMappingHandlerAdapter
, or ExceptionHandlerExceptionResolver
, you can declare a WebMvcRegistrationsAdapter
instance to provide such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration
annotated with @EnableWebMvc
.
扩展SpringMVC
编写一个配置类(@Configuration),是WebMvcConfigurer类型,而且不能标注@EnableWebMvc
可用下面两种方法扩展SpringMVC
①implements WebMvcConfigurer(官方推荐)
②extends WebMvcConfigurationSupport
使用第一种方法是实现了一个接口,可以任意实现里面的方法,不会影响到Spring Boot自身的@EnableAutoConfiguration,(idea中Ctrl+O显示所有可实现方法列表)
而使用第二种方法相当于覆盖了@EnableAutoConfiguration里的所有方法,每个方法都需要重写,比如,若不实现方法addResourceHandlers(),则会导致静态资源无法访问,实现的方法如下:
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/META-INF/resources/")
.addResourceLocations("classpath:/resources/")
.addResourceLocations("classpath:/static/")
.addResourceLocations("classpath:/public/");
super.addResourceHandlers(registry);
}
所以,第一种比较好
@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(
name = {"viewResolver"},
value = {ContentNegotiatingViewResolver.class}
)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
resolver.setOrder(-2147483648);
return resolver;
}
原理
- WebMvcAutoConfiguration是SpringMVC的自动配置类
- 容器中所有的WebMvcConfigurer都会起作用
- 我们的配置类也会被调用
效果:SpringMVC的自动配置和我们的扩展配置都会起作用
全面接管SpringMVC
SpringBoot对SpringMVC的自动配置都不需要了,所有都是自己配。
我们需要在配置类中添加@EnableWebMvc后自动配置就失效了
原理:
为什么写这个就失效了
@EnableWebMvc的核心
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
DelegatingWebMvcConfiguration.class
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {...}
WebMvcAutoConfiguration
@Configuration
@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 {....}
所以,原因就是@EnableWebMvc将WebMvcConfigurationSupport组件导进来了,导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能
定制自己的解析器:
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
@Bean
public ViewResolver myViewResoler(){
return new MyViewResoler();
}
public static class MyViewResoler implements ViewResolver{
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
}
测试一下
image.png
随便访问一个页面后,查看到了我们自己的视图解析器
image.png
org.springframework.boot.autoconfigure.web:web的所有自动场景
如何修改SpringBoot的自动配置
模式:
- SpringBoot在自动配置很多组件的时候,会先看用户是否自己配置了(@Bean ,@Component)如果有就用用户配置的,如果没有就自动配置。如果有些组件可以有多个(ViewResolver),就将用户配置的和自动默认的组合起来。
- SpringBoot中会有非常多的XXXConfigurer帮助我们进行扩展配置