How to Check if a Variable Is Defined in Thymeleaf – 如何检查 Thymeleaf 中是否定义了变量

最后修改: 2024年 2月 11日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.导言

In this tutorial, we’ll learn how to check if a variable is defined in Thymeleaf using three different methods. For this purpose, we’ll use Spring MVC and Thymeleaf to build a simple web application with a single view that displays the server date and time if a given variable is set.

在本教程中,我们将学习如何使用三种不同的方法检查 Thymeleaf 中是否定义了变量。为此,我们将使用 Spring MVC 和 Thymeleaf 构建一个简单的 Web 应用程序,其中包含一个视图,如果设置了给定的变量,该视图将显示 服务器日期和时间

2. Setup

2.设置

Before diving into the methods, we need to do some initial setup. Let’s start with the Thymeleaf dependencies:

在深入研究方法之前,我们需要进行一些初始设置。让我们从 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>

Now, let’s create the checkVariableIsDefined view:

现在,让我们创建 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>

Let’s also define two new endpoints for this view:

我们还要为这个视图定义两个新的端点:

@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";
}

The first endpoint loads the checkVariableIsDefined view with the serverTime variable defined, whereas the latter endpoint loads the same view without the variable defined.

第一个端点加载的是定义了 serverTime 变量的 checkVariableIsDefined 视图,而后一个端点加载的是未定义变量的同一视图。

This setup will help us test the methods presented in the following sections.

这种设置将有助于我们测试下文介绍的方法。

3. Using the #ctx Object

3.使用 #ctx 对象

The first method we’ll explore uses the context object, which contains all the variables the Thymeleaf template engine needs to process templates, including a reference to the Locale used for externalized messages. The context is an implementation of the IContext interface for standalone applications or the IWebContext interface for web applications.

我们将探讨的第一个方法使用上下文对象,该对象包含 Thymeleaf 模板引擎处理模板所需的所有变量,包括外部化消息使用的 Locale 引用。上下文是独立应用程序的 IContext 接口或 Web 应用程序的 IWebContext 接口的实现。

We can access the context object in a Thymeleaf template using the #ctx notation. Let’s add the relevant code to the checkVariableIsDefined view:

我们可以使用 #ctx 符号访问 Thymeleaf 模板中的上下文对象。让我们将相关代码添加到 checkVariableIsDefined 视图中:

<div th:if="${#ctx.containsVariable('serverTime')}" th:text="'Server Time Using the #ctx Object Is: ' + ${serverTime}"/>

Now, let’s write two integration tests to verify this method:

现在,让我们编写两个集成测试来验证这种方法:

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. Using the if Conditional

4.使用 if 条件式

The following method uses the if conditional. Let’s update the checkVariableIsDefined view:

下面的方法使用了 if 条件。让我们更新 checkVariableIsDefined 视图:

<div th:if="${serverTime}" th:text="'Server Time Using #th:if Conditional Is: ' + ${serverTime}"/>

If the variable is null, the if conditional is evaluated as false.

如果变量为空,if条件将被评估为false

Now, let’s take a look at the integration tests:

现在,让我们来看看集成测试:

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))));
}

The if conditional is evaluated as true if any of the following conditions is true:

如果以下任何条件为真,if条件将被评估为true

  • the variable is a boolean with the value true
  • the variable is a non-zero number
  • the variable is a non-zero character
  • the variable is a string different than “false”, “off”, “no”
  • the variable is not a boolean, a number, a character, or a string

Note that if the variable is set, but has the value “false”, “no”, “off”, or 0, then the if conditional is evaluated as false, which might cause some undesired side effects if our intention is to only check if the variable is set. Let’s illustrate this by updating the view:

请注意,如果变量已设置,但其值为 “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"'/>

Next, let’s create the integration test:

接下来,让我们创建集成测试:

@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"))));
}

We could address this issue by checking that the variable is not null:

我们可以通过检查变量是否为空来解决这个问题:

<div th:if="${serverTime != null}" th:text="'Server Time Using #th:if Conditional Is: ' + ${serverTime}"/>

5. Using the unless Conditional

5.使用 unless 条件式

The last method uses unless which is the inverse of the if conditional. Let’s update the view accordingly:

最后一种方法使用 unless,它是 if 条件的反向。让我们相应地更新视图:

<div th:unless="${serverTime == null}" th:text="'Server Time Using #th:unless Conditional Is: ' + ${serverTime}"/>

Let’s also test whether this method produces the expected results:

我们也来测试一下这种方法是否能产生预期的结果:

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. Conclusion

6.结论

In this article, we’ve learned three methods for checking if a variable is defined in Thymeleaf. The first method uses the #ctx object and the containsVariable method, whereas the second and last methods use the conditional statements if and its inverse unless.

在本文中,我们学习了三种检查 Thymeleaf 中是否定义了变量的方法。第一种方法使用了 #ctx 对象和 containsVariable 方法,而第二种和最后一种方法则使用了条件语句 if 及其反义词 unless

As always, the complete code can be found over on GitHub.

与往常一样,完整的代码可以在 GitHub 上找到