模板引擎 thymeleaf、ContentNegotiatingViewResolver视图解析器(内容协商视图解析器)、格式化转换器
模板引擎 thymeleaf
SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样的,什么样一个思想呢我们来看一下这张图。
模板引擎的使用:是为了实现数据分离(动态数据与静态数据)和代码重用
1、Thymeleaf 官网
2、Github
3、Spring官方文档
thymeleaf 的依赖:
<!--thymeleaf模板-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
我们要使用thymeleaf,需要在html文件中导入命名空间的约束,
<html xmlns:th="http://www.thymeleaf.org">
Thymeleaf 的配置类
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
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";
private Charset encoding;
}
我们可以在其中看到默认的前缀和后缀!我们只需要把我们的html页面放在类路径下的templates下,thymeleaf就可以帮我们自动渲染了。
thymeleaf语法
我们可以使用任意的 th:* 来替换Html中原生属性的值
// 常用的标签 #4
Variable Expressions: ${...}:获取变量值、获取对象的属性、调用方法;
Message Expressions: #{...}:获取国际化内容;
Link URL Expressions: @{...}:定义URL;
<link th:href="@{/css/dashboard.css}" rel="stylesheet">
<script th:src="@{/js/jquery-3.2.1.slim.min.js}"></script>
Fragment Expressions: ~{...}:片段引用表达式
<div th:insert="~{commons :: main}">...</div>
// 常用的运算符
Boolean operations:(布尔运算)
Binary operators: and , or
Boolean negation (一元运算符): ! , not
Comparisons and equality:(比较运算)
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Arithmetic operations:(数学运算)
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Text operations:(文本操作)
String concatenation: +
Literal substitutions: |The name is ${name}|
Conditional operators:条件运算(三元运算符)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
// ======================================
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 ,…
Special tokens:
No-Operation: _
// ======================================
Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;
补充:配合 th:object="${session.user}:
<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>
// =======================================
// 内置的工具对象 #19
#execInfo :有关正在处理的模板的信息。
#messages :在变量表达式中获取外部化消息的方法,与使用{{…}语法获取外部化消息的方法相同。
#uri:转义部分url/uri的方法
#conversions :执行配置的转换服务(如果有的话)的方法。
#dates :java.util.Date对象的方法:格式化、组件提取等。
#calendars :类似于日期,但适用于java.util.Calendar对象。
#numbers :格式化数字对象的方法。
#strings :字符串对象的方法:contains、startsWith、prepending/appending等。
#objects :通常用于对象的方法。
#bools:布尔求值的方法。
#arrays :数组的方法。
#lists:列表的方法。
#sets :集合的方法。
#maps :Map的方法。
#aggregates :在数组或集合上创建聚合的方法。
#ids:处理可能重复的id属性的方法(例如,作为迭代的结果)。
// 内置的基本对象: #18
#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.
很多样式,我们即使现在学习了,也会忘记,所以我们在学习过程中,需要使用什么,根据官方文档来查询,才是最重要的,要熟练使用官方文档!
简单使用:
th:each
- controller
@GetMapping("/emps")
public String list(Model model) {
Collection<Employee> emps = employeeDao.getAllEmployee();
model.addAttribute("emps", emps);
return "emp/list";
}
- list.html
th:fragment
- bar.html
<!--导航栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" th:text="${session.loginUser}"></a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" th:href="@{/user/logout}">注销</a>
</li>
</ul>
</nav>
<div th:replace="~{commons/bar::topbar}"></div>
ContentNegotiatingViewResolver
目的:看看该 ContentNegotiatingViewResolver
视图解析器作用
首先在 WebMvcAutoConfiguration
找到注册的 Bean
@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使用所有其他视图解析器来定位
// 设置该视图为较高的优先级
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
点进 ContentNegotiatingViewResolver
类
找到对应的解析视图的代码:resolveViewName()
注解说明:@Nullable 即参数可为null
点进去
由此可得结论:ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的
继续往下看 getCandidateViews()方法
:
getBestView()方法
最终上述我们获得的视图都会返回到 调用者处。即 DiapatcherServlet 的 resolverViewName()方法
简要的调用关系如下:
因此,如果我要自定义视图解析器,需要首先实现 ViewResolver
接口,然后再将实现了该接口的类交给 Spring 的 Ioc 容器托管,使之成为一个 Bean。
public class MyViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
// 在容器中注册 bean
@Bean
public ViewResolver myViewResolver() {
return new MyViewResolver();
}
}
如何检验我们写的视图解析器起效了?
在DispathcerServlet类的 doDispatch()方法内 Debug一下即可:
ContentNegotiatingViewResolver
是 ViewResolver
的实现类,该解析基于 请求文件名(也就是:文件扩展名) 或请求头 Accept 解析视图。
ContentNegotiatingViewResolver
不会自行解析视图,而是委托给其他 ViewResolvers。
默认情况下,这些其他视图解析器会从应用程序上下文中自动获取。
此视图解析器通过配置的 ContentNegotiationManager
确定请求的媒体类型(也就是Mime 类型)。
确定请求的媒体类型后,此解析器向每个委托视图解析器查询 View,并确定请求的媒体类型是否与视图的 MediaType 兼容。返回最兼容的视图。
请注意,这些默认视图是作为候选者提供的,但仍需要具有请求的内容类型(通过文件扩展名,参数,Accept 请求头)。
例如,如果请求路径为:localhost:8080/view.html,则此视图解析器将查找具有 text / html内容类型。如果请求头是:Accept: text/html ;也具有相同的结果。
格式化转换器
在WebMvcAutoConfiguration
中:
@Bean
@Override
public FormattingConversionService mvcConversionService() {
WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
addFormatters(conversionService);
return conversionService;
}
点击:getDateFormat()
发现SpringBoot默认的日期格式为:dd/MM/yyyy
我们可以在配置文件中配置日期格式化的规则,如果我们没配,会使用SpringBoot默认的日期格式。
- application.yaml
# 自定义日期格式化
spring.mvc.date-format=yyyy-MM-dd