1. 引言
在这个教程中,我们将学习如何使用三种不同的方法检查Thymeleaf中是否存在一个变量。我们将使用Spring MVC和Thymeleaf构建一个简单的Web应用,该应用有一个视图,如果给定的变量已设置,它将显示服务器日期和时间。
2. 准备工作
在深入方法之前,我们需要做一些初始设置。首先,添加Thymeleaf的依赖项:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
接下来,创建checkVariableIsDefined
视图:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
th:with="lang=${#locale.language}" th:lang="${lang}">
<head>
<title>How to Check if a Variable is Defined in Thymeleaf</title>
</head>
<body>
<!-- we'll add here the relevant code for each method -->
</body>
</html>
再定义两个新的端点来处理这个视图:
@RequestMapping(value = "/variable-defined", method = RequestMethod.GET)
public String getDefinedVariables(Model model) {
DateFormat dateFormat =
DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.getDefault());
model.addAttribute("serverTime", dateFormat.format(new Date()));
return "checkVariableIsDefined.html";
}
@RequestMapping(value = "/variable-not-defined", method = RequestMethod.GET)
public String getNotDefinedVariables(Model model) {
return "checkVariableIsDefined.html";
}
第一个端点加载带有serverTime
变量的checkVariableIsDefined
视图,而第二个端点加载不带变量的相同视图。
这个设置将帮助我们在接下来的章节中测试所介绍的方法。
3. 使用#ctx
对象
我们首先探索的方法是使用上下文对象,它包含了Thymeleaf模板引擎处理模板所需的所有变量,包括用于外部化消息的Locale
引用。上下文是一个独立应用的IContext
接口的实现,或者对于Web应用是IWebContext
接口的实现。
在Thymeleaf模板中,我们可以使用#ctx
语法访问上下文对象。现在,让我们在checkVariableIsDefined
视图中添加相关代码:
<div th:if="${#ctx.containsVariable('serverTime')}" th:text="'Server Time Using the #ctx Object Is: ' + ${serverTime}"/>
接下来,编写两个集成测试以验证此方法:
private static final String CTX_OBJECT_MSG = "Server Time Using the #ctx Object Is: ";
@Test
public void whenVariableIsDefined_thenCtxObjectContainsVariable() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/variables-defined"))
.andExpect(status().isOk())
.andExpect(view().name("checkVariableIsDefined.html"))
.andExpect(content().string(containsString(CTX_OBJECT_MSG)));
}
@Test
public void whenVariableNotDefined_thenCtxObjectDoesNotContainVariable() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/variables-not-defined"))
.andExpect(status().isOk())
.andExpect(view().name("checkVariableIsDefined.html"))
.andExpect(content().string(not(containsString(CTX_OBJECT_MSG))));
}
4. 使用if
条件语句
接下来的方法使用if
条件语句。更新checkVariableIsDefined
视图:
<div th:if="${serverTime}" th:text="'Server Time Using #th:if Conditional Is: ' + ${serverTime}"/>
如果变量为null,if
条件将被评估为false
。
现在,看看集成测试:
private static final String IF_CONDITIONAL_MSG = "Server Time Using #th:if Conditional Is: ";
@Test
public void whenVariableIsDefined_thenIfConditionalIsTrue() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/variable-defined"))
.andExpect(status().isOk())
.andExpect(view().name("checkVariableIsDefined.html"))
.andExpect(content().string(containsString(IF_CONDITIONAL_MSG)));
}
@Test
public void whenVariableIsNotDefined_thenIfConditionalIsFalse() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/variable-not-defined"))
.andExpect(status().isOk())
.andExpect(view().name("checkVariableIsDefined.html"))
.andExpect(content().string(not(containsString(IF_CONDITIONAL_MSG))));
}
if
条件语句只有在以下任一条件为真时才会被评估为true
:
- 变量是一个布尔值,其值为
true
- 变量是一个非零数字
- 变量是一个非零字符
- 变量是一个不同于
"false"
、"off"
或"no"
的字符串 - 变量既不是布尔值、数字、字符也不是字符串
请注意,如果变量已设置,但值为"false"
、"no"
、"off"
或0
,那么if
条件将被评估为false
,这可能会导致意外的副作用,如果我们的目的是仅检查变量是否已设置。让我们通过更新视图来说明这一点:
<div th:if='${"false"}' th:text='"Evaluating \"false\"'/>
<div th:if='${"no"}' th:text='"Evaluating \"no\"'/>
<div th:if='${"off"}' th:text='"Evaluating \"off\"'/>
<div th:if="${0}" th:text='"Evaluating 0"'/>
然后,编写集成测试:
@Test
public void whenVariableIsDefinedAndNotTrue_thenIfConditionalIsFalse() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/variable-defined"))
.andExpect(status().isOk())
.andExpect(view().name("checkVariableIsDefined.html"))
.andExpect(content().string(not(containsString("Evaluating \"false\""))))
.andExpect(content().string(not(containsString("Evaluating \"no\""))))
.andExpect(content().string(not(containsString("Evaluating \"off\""))))
.andExpect(content().string(not(containsString("Evaluating 0"))));
}
我们可以解决这个问题,通过检查变量是否不为null:
<div th:if="${serverTime != null}" th:text="'Server Time Using #th:if Conditional Is: ' + ${serverTime}"/>
5. 使用unless
条件语句
最后一个方法使用unless
,它是if
条件语句的逆否命题。相应地更新视图:
<div th:unless="${serverTime == null}" th:text="'Server Time Using #th:unless Conditional Is: ' + ${serverTime}"/>
我们也测试一下这个方法是否产生预期结果:
private static final String UNLESS_CONDITIONAL_MSG = "Server Time Using #th:unless Conditional Is: ";
@Test
public void whenVariableIsDefined_thenUnlessConditionalIsTrue() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/variable-defined"))
.andExpect(status().isOk())
.andExpect(view().name("checkVariableIsDefined.html"))
.andExpect(content().string(containsString(IF_CONDITIONAL_MSG)));
}
@Test
public void whenVariableIsNotDefined_thenUnlessConditionalIsFalse() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/variable-not-defined"))
.andExpect(status().isOk())
.andExpect(view().name("checkVariableIsDefined.html"))
.andExpect(content().string(not(containsString(UNLESS_CONDITIONAL_MSG))));
}
6. 总结
在这篇文章中,我们学习了在Thymeleaf中检查变量是否已定义的三种方法。第一种方法使用#ctx
对象和containsVariable
方法,而第二种和第三种方法使用条件语句if
及其逆否命题unless
。
如往常一样,完整的代码可以在GitHub上找到。