概述:Thymeleaf 3.0在Spring MVC中的新特性
Thymeleaf是一款用于处理和创建HTML、XML、JavaScript、CSS和纯文本的Java模板引擎。对于Thymeleaf和Spring的入门介绍,可以参考这篇文章:Thymeleaf与Spring集成。
本文将探讨Thymeleaf 3.0在Spring MVC应用中新增的功能,包括自然处理和内联JavaScript。版本3引入了新的模板模式和底层改进。具体来说,我们将涉及纯文本、JavaScript和CSS模板处理的主题。
Thymeleaf 3.0包含三种新的文本模板模式:TEXT
、JAVASCRIPT
和CSS
,分别用于处理纯文本、JavaScript和CSS模板。
1. Maven依赖
首先,让我们看看如何将Thymeleaf与Spring集成。在项目依赖中需要添加thymeleaf-spring
库:
注意,对于Spring 4项目,应使用thymeleaf-spring4
库,而不是thymeleaf-spring5
。最新的依赖版本可以在这里找到。
2. Java Thymeleaf配置
首先,我们需要配置新的模板引擎、视图解析器和模板解析器。为此,需要更新之前创建的Java配置类,如这里所示。除了新的解析器类型,我们的模板还需要实现Spring接口ApplicationContextAware
:
@Configuration
@EnableWebMvc
@ComponentScan({ "com.baeldung.thymeleaf" })
public class WebMVCConfig implements WebMvcConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
// Java setter
@Bean
public ViewResolver htmlViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine(htmlTemplateResolver()));
resolver.setContentType("text/html");
resolver.setCharacterEncoding("UTF-8");
resolver.setViewNames(ArrayUtil.array("*.html"));
return resolver;
}
@Bean
public ViewResolver javascriptViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine(javascriptTemplateResolver()));
resolver.setContentType("application/javascript");
resolver.setCharacterEncoding("UTF-8");
resolver.setViewNames(ArrayUtil.array("*.js"));
return resolver;
}
@Bean
public ViewResolver plainViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine(plainTemplateResolver()));
resolver.setContentType("text/plain");
resolver.setCharacterEncoding("UTF-8");
resolver.setViewNames(ArrayUtil.array("*.txt"));
return resolver;
}
}
如上所述,我们创建了三个不同的视图解析器,分别针对HTML视图、JavaScript文件和纯文本文件。Thymeleaf通过检查文件扩展名来区分它们:.html
、.js
和.txt
。
我们还创建了一个静态ArrayUtil
类,以使用array()
方法创建包含视图名称的字符串数组。
接下来,在该类的其余部分,我们需要配置模板引擎:
private ISpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver);
return engine;
}
最后,我们需要创建三个独立的模板解析器:
private ITemplateResolver htmlTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/views/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
private ITemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/js/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
return resolver;
}
private ITemplateResolver plainTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/txt/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.TEXT);
return resolver;
}
请注意,为了便于测试,最好使用非缓存模板,因此推荐使用setCacheable(false)
方法。
JavaScript模板将存储在/WEB-INF/js
文件夹中,纯文本文件在/WEB-INF/txt
文件夹中,而HTML文件的路径是/WEB-INF/html
。
3. Spring控制器配置
为了测试新配置,我们创建了一个Spring控制器:
@Controller
public class InliningController {
@RequestMapping(value = "/html", method = RequestMethod.GET)
public String getExampleHTML(Model model) {
model.addAttribute("title", "Baeldung");
model.addAttribute("description", "Thymeleaf tutorial");
return "inliningExample.html";
}
@RequestMapping(value = "/js", method = RequestMethod.GET)
public String getExampleJS(Model model) {
model.addAttribute("students", StudentUtils.buildStudents());
return "studentCheck.js";
}
@RequestMapping(value = "/plain", method = RequestMethod.GET)
public String getExamplePlain(Model model) {
model.addAttribute("username", SecurityContextHolder.getContext()
.getAuthentication().getName());
model.addAttribute("students", StudentUtils.buildStudents());
return "studentsList.txt";
}
}
在HTML示例中,我们将展示如何使用新内联功能,以及带有和不带HTML标签转义的情况。
对于JS示例,我们将生成一个AJAX请求,加载包含学生信息的js文件。请注意,我们在StudentUtils
类的简单buildStudents()
方法中使用了它,参见这篇文章。
在纯文本示例中,我们将显示学生信息作为文本文件。使用纯文本模板模式的一个典型例子可能是发送纯文本电子邮件。
此外,我们将使用SecurityContextHolder
获取已登录用户的用户名。
4. HTML/JS/Text示例文件
教程的最后部分是创建三种不同类型的文件,并测试Thymeleaf新特性的用法。让我们从HTML文件开始:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Inlining example</title>
</head>
<body>
<p>Title of tutorial: [[${title}]]</p>
<p>Description: [(${description})]</p>
</body>
</html>
在这个文件中,我们采用了两种不同的方法。为了显示标题,我们使用转义语法,这将移除所有HTML标签,只显示文本。描述部分使用未转义语法,保留HTML标签。最终效果如下:
<p>Title of tutorial: Baeldung</p>
<p>Description: <strong>Thymeleaf</strong> tutorial</p>
浏览器会解析这个内容,将单词Thymeleaf以粗体样式显示出来。
接下来,我们测试JavaScript模板特性:
var count = [[${students.size()}]];
alert("Number of students in group: " + count);
在JAVASCRIPT
模板模式中,属性将以JavaScript未转义的方式呈现。这将导致创建一个弹出警告。我们在listStudents.html文件中使用jQuery AJAX加载这个警告:
<script>
$(document).ready(function() {
$.ajax({
url : "/spring-thymeleaf/js",
});
});
</script>
最后但同样重要的是,我们要测试纯文本文件生成。我们创建了一个名为studentsList.txt的文件,内容如下:
Dear [(${username})],
This is the list of our students:
[# th:each="s : ${students}"]
- [(${s.name})]. ID: [(${s.id})]
[/]
Thanks,
The Baeldung University
与标记模板模式一样,标准方言仅包含一个可处理元素\[# ... \]
和一组可处理属性(如th:text
、th:utext
、th:if
、th:unless
和th:each
等)。结果将是一个文本文件,可用于例如电子邮件,如第3节末尾所述。
如何测试? 我们的建议是先在浏览器中尝试,然后检查现有的JUnit测试。
5. Thymeleaf在Spring Boot中的应用
Spring Boot通过添加spring-boot-starter-thymeleaf
依赖提供了对Thymeleaf的自动配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
无需显式配置。默认情况下,HTML文件应放在resources/templates
目录下。
6. 结论
本文讨论了Thymeleaf框架在3.0版本中实现的新功能。完整实现可在GitHub项目中找到,这是一个基于Eclipse的项目,适合在现代浏览器中进行测试。
如果你计划从2.x版本迁移到最新版本,可以查看迁移指南。值得注意的是,你的现有Thymeleaf模板几乎与Thymeleaf 3.0完全兼容,只需在配置中做少许修改即可。