30.SpringBoot学习笔记–Thymeleaf语法
Thymeleaf 自动渲染
只要把 HTML 页面放在 classpath:/templates/,Thymeleaf 就能自动渲染。
参考 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
}
示例
HelloController
package demo.yangxu.springboot.controller;
@Controller
public class HelloController {
@RequestMapping("/success")
public String success(){
//classpath:/templates/success.html
return "success";
}
}
创建 success.html,路径为:src\main\resources\templates\success.html
在浏览器中访问:
http://localhost:8080/success
Thymeleaf 使用方法
官方文档:
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
示例
查出一些数据,在页面展示。
HelloController
package demo.yangxu.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
@Controller
public class HelloController {
@RequestMapping("/success")
public String success(Map<String,Object> map){
map.put("hello","你好");
return "success";
}
}
src\main\resources\templates\success.html
1、导入 Thymeleaf 的名称空间
<html xmlns:th="http://www.thymeleaf.org">
参考:using-texts
2、使用 Thymeleaf 语法
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>success!</h1>
<!--th:text 设置div里面的文本内容 -->
<div th:text="${hello}">这是显示欢迎信息</div>
</body>
</html>
3、访问
http://localhost:8080/success
4、访问结果
Thymeleaf 语法规则
th:text
改变当前元素内的文本内容
th
对于任意 html 属性,替换原生属性的值
例如:
<div id="div01" class="myDiv" th:id="${hello}" th:class="${hello}" th:text="${hello}">这是显示欢迎信息</div>
启动项目后,在浏览器中访问,查看网页的源代码:
<div id="你好" class="你好">你好</div>
div 中的 id 和 class 属性均被替换。
官网给出的所有 th 类 attribute:
Order | Feature | Attributes |
---|---|---|
1 | Fragment inclusion | th:insert th:replace |
2 | Fragment iteration | th:each |
3 | Conditional evaluation | th:if th:unless th:switch th:case |
4 | Local variable definition | th:object th:with |
5 | General attribute modification | th:attr th:attrprepend th:attrappend |
6 | Specific attribute modification | th:value th:href th:src ... |
7 | Text (tag body modification) | th:text th:utext |
8 | Fragment specification | th:fragment |
9 | Fragment removal | th:remove |
与 JSP 类比:
Order | Feature | Attributes |
---|---|---|
1 | 片段包含 jsp:include | th:insert th:replace |
2 | 遍历 c:forEach | th:each |
3 | 条件判断 c:if | th:if th:unless th:switch th:case |
4 | 声明变量 c:set | th:object th:with |
5 | 任意属性修改 支持prepend,append | th:attr th:attrprepend th:attrappend |
6 | 修改指定属性默认值 | th:value th:href th:src ... |
7 | 修改标签体内容 | th:text(转义特殊字符) th:utext(不转义特殊字符) |
8 | 声明片段 | th:fragment |
9 | 移除片段 | th:remove |
表达式
官网给出的表达式语法:
- Simple expressions:
- Variable Expressions:
${...}
- Selection Variable Expressions:
*{...}
- Message Expressions:
#{...}
- Link URL Expressions:
@{...}
- Fragment Expressions:
~{...}
- Variable 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 literals:
- Text operations【文本操作】:
- String concatenation:
+
- Literal substitutions:
|The name is ${name}|
- String concatenation:
- Arithmetic operations【数学运算】:
- Binary operators:
+
,-
,*
,/
,%
- Minus sign (unary operator):
-
- Binary operators:
- Boolean operations【布尔运算】:
- Binary operators:
and
,or
- Boolean negation (unary operator):
!
,not
- Binary operators:
- Comparisons and equality【比较运算】:
- Comparators:
>
,<
,>=
,<=
(gt
,lt
,ge
,le
) - Equality operators:
==
,!=
(eq
,ne
)
- Comparators:
- Conditional operators【条件运算(三元运算符)】:
- If-then:
(if) ? (then)
- If-then-else:
(if) ? (then) : (else)
- Default:
(value) ?: (defaultvalue)
- If-then:
- Special tokens:
- No-Operation:
_
- No-Operation:
Variable Expressions: ${...}
获取变量值,可以使用 OGNL。
官网给出的 OGNL 示例:
/*
* Access to properties using the point (.). Equivalent to calling property getters.
*/
${person.father.name}
/*
* Access to properties can also be made by using brackets ([]) and writing
* the name of the property as a variable or between single quotes.
*/
${person['father']['name']}
/*
* If the object is a map, both dot and bracket syntax will be equivalent to
* executing a call on its get(...) method.
*/
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}
/*
* Indexed access to arrays or collections is also performed with brackets,
* writing the index without quotes.
*/
${personsArray[0].name}
/*
* Methods can be called, even with arguments.
*/
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}
参考:variables
高级特性:
1、获取对象的属性、调用方法;
2、使用内置的基本对象:
#ctx
: the context object.#vars:
the context variables.#locale
: the context locale.#request
: (only in Web Contexts) theHttpServletRequest
object.#response
: (only in Web Contexts) theHttpServletResponse
object.#session
: (only in Web Contexts) theHttpSession
object.#servletContext
: (only in Web Contexts) theServletContext
object.
参考:Appendix A: Expression Basic Objects
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 forjava.util.Date
objects: formatting, component extraction, etc.#calendars
: analogous to#dates
, but forjava.util.Calendar
objects.#numbers
: methods for formatting numeric objects.#strings
: methods forString
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).
参考:Appendix B: Expression Utility Objects
Selection Variable Expressions: *{...}
变量的选择表达式,和 ${} 在功能上是一样。与 ${} 不同在于,可以配合 th:object=”${session.user} 使用。
官网给出的说明和示例:
And what is a selected object? The result of an expression using the th:object
attribute. Let’s use one in our user profile (userprofile.html
) page:
<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>
Which is exactly equivalent to:
<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>
Of course, dollar and asterisk syntax can be mixed:
<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
When an object selection is in place, the selected object will also be available to dollar expressions as the #object
expression variable:
<div th:object="${session.user}">
<p>Name: <span th:text="${#object.firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
As said, if no object selection has been performed, dollar and asterisk syntaxes are equivalent.
<div>
<p>Name: <span th:text="*{session.user.name}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{session.user.surname}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{session.user.nationality}">Saturn</span>.</p>
</div>
参考:Expressions on selections (asterisk syntax)
Message Expressions: #{...}
获取国际化内容。
参考:Messages
Link URL Expressions: @{...}
定义 URL。
官网给出的示例:
<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html"
th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
<!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
If several parameters are needed, these will be separated by commas: @{/order/process(execId=${execId},execType='FAST')}
参考:Link URLs
Fragment Expressions: ~{...}
片段引用表达式。
官网给出的示例:
<div th:insert="~{commons :: main}">...</div>
参考:Fragments
Iteration
官网给出的示例:
For our product list page, we will need a controller method that retrieves the list of products from the service layer and adds it to the template context:
public void process(
final HttpServletRequest request, final HttpServletResponse response,
final ServletContext servletContext, final ITemplateEngine templateEngine)
throws Exception {
ProductService productService = new ProductService();
List<Product> allProducts = productService.findAll();
WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
ctx.setVariable("prods", allProducts);
templateEngine.process("product/list", ctx, response.getWriter());
}
And then we will use th:each
in our template to iterate over the list of products:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<h1>Product list</h1>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
</table>
<p>
<a href="../home.html" th:href="@{/}">Return to home</a>
</p>
</body>
</html>
参考:Iteration
Inlining
官网给出的示例:
Although the Standard Dialect allows us to do almost everything using tag attributes, there are situations in which we could prefer writing expressions directly into our HTML texts. For example, we could prefer writing this:
<p>Hello, [[${session.user.name}]]!</p>
Expressions between [[...]]
or [(...)]
are considered inlined expressions in Thymeleaf, and inside them we can use any kind of expression that would also be valid in a th:text
or th:utext
attribute.
Note that, while [[...]]
corresponds to th:text
(i.e. result will be HTML-escaped), [(...)]
corresponds to th:utext
and will not perform any HTML-escaping.
参考:Inlining
示例
HelloController
package demo.yangxu.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Arrays;
import java.util.Map;
@Controller
public class HelloController {
@RequestMapping("/success")
public String success(Map<String,Object> map){
map.put("hello","<h1>你好</h1>");
map.put("users", Arrays.asList("zhangsan","lisi","wangwu"));
return "success";
}
}
templates\success.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>成功!</h1>
<!--th:text 设置div里面的文本内容 -->
<div id="div01" class="myDiv" th:id="${hello}" th:class="${hello}" th:text="${hello}">这是显示欢迎信息</div>
<hr/>
<div th:text="${hello}"></div>
<div th:utext="${hello}"></div>
<hr/>
<!-- th:each每次遍历都会生成当前这个标签: 3个h4 -->
<h4 th:text="${user}" th:each="user:${users}"></h4>
<hr/>
<h4>
<span th:each="user:${users}">[[${user}]]</span>
</h4>
</body>
</html>
运行效果:
运行后的网页源码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>成功!</h1>
<!--th:text 设置div里面的文本内容 -->
<div id="<h1>你好</h1>" class="<h1>你好</h1>"><h1>你好</h1></div>
<hr/>
<div><h1>你好</h1></div>
<div><h1>你好</h1></div>
<hr/>
<!-- th:each每次遍历都会生成当前这个标签: 3个h4 -->
<h4>zhangsan</h4>
<h4>lisi</h4>
<h4>wangwu</h4>
<hr/>
<h4>
<span>zhangsan</span><span>lisi</span><span>wangwu</span>
</h4>
</body>
</html>