使用 Thymeleaf 算术的意外结果
Unexpected result using Thymeleaf arithmetic
我有一个 Thymeleaf 模板,没有使用任何 Spring 或 SpEL - 只是 Thymeleaf 标准方言。
模板的相关部分是:
<div>
<span>Inactive: </span>
<span th:text="${total - active}"></span>
</div>
测试 1
如果我的模型填充如下:
model.put("total", 10);
model.put("active", 7);
然后我得到了预期的结果:
<div>
<span>Inactive: </span>
<span>3</span>
</div>
测试 2
但是如果模型值中的一个(或两个)为空:
model.put("total", null);
model.put("active", 7);
然后我得到了意想不到的结果。有了上面的数据,我得到:
<div>
<span>Inactive: </span>
<span>-7.0</span>
</div>
换句话说,null
被计算为浮点数0.0
,因此计算结果为-7.0
。
我原以为它会抛出一个运行时错误,这是由于尝试对空值执行算术而引起的。
测试 3
如果我稍微更改模板并使用与测试 2 相同的数据:
<div>
<span>Inactive: </span>
<span th:text="${total} - ${active}"></span>
</div>
我收到以下运行时错误 - 这是我对测试 2 的预期:
org.thymeleaf.exceptions.TemplateProcessingException: Cannot execute subtraction: operands are "null" and "7"
为什么测试 2 生成了有效的 HTML 而不是抛出错误的计算结果?
(我知道我需要预先处理这些 null
值以避免出现问题,但这种无声的非故障是一个问题。)
快速解答
您应该明确地预先处理 null
值,如问题中所述。
您还应注意 Thymeleaf 的减号运算符与 OGNL 的减号运算符之间的不一致行为。
建议:使用 Thymeleaf 减号运算符。
更详细的解释如下...
Thymeleaf 和 OGNL
当您使用标准 Thymeleaf 方言时,开头 ${
和结尾 }
内的表达式由 OGNL 处理。来自 the official documentation:
This is a variable expression, and it contains an expression in a language called OGNL (Object-Graph Navigation Language) that will be executed on the context variables map...
您可以阅读有关 OGNL 及其语法的信息 here。 Thymeleaf 版本 3.0.12 使用 ognl-3.1.26.jar
库。
因此,当您使用 ${total - active}
时,整个表达式(包括减法)都由 OGNL 处理。
但是,当您使用 ${total} - ${active}
时,这实际上是两个单独的 OGNL 表达式,它们之间有一个减号。
在第一种情况下,执行减法是 OGNL 的责任。但在第二种情况下,减法是由 Thymeleaf 在将两个 ${...}
表达式的评估委托给 OGNL 之后执行的。
Thymeleaf 的大多数运算符通常表现出与 OGNL 相同的行为。但在这种特定情况下,Thymeleaf 减号运算符在处理 null
值时与 OGNL 减号运算符 的行为不同。
我认为 Thymeleaf 行为是不那么令人惊讶的方法。
Spring 和 SpEL
如果您将 Spring 与 Thymeleaf 一起使用,则 ${
和 }
中的所有表达式都将委托给 SpEL(Spring Expression Language)- 并且 OGNL 不会在全部.
在这种情况下,表达式 ${total - active}
将不再在运行时“成功”。相反,它会抛出 SpEL 异常:
org.springframework.expression.spel.SpelEvaluationException: EL1030E: The operator 'SUBTRACT' is not supported between objects of type 'null' and 'java.lang.Integer'
因此,SpEL 和 Thymeleaf 标准方言彼此一致 - 而 OGNL 是少数。
OGNL 真的在这里将 null 评估为零吗?
是的 - 我们可以证明在一个简单的 Java 程序中使用 OGNL:
依赖关系:
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.3.0</version>
<!-- same behavior:
<version>3.2.21</version>
-->
</dependency>
Java演示:
import ognl.Ognl;
import ognl.OgnlException;
public class NullDemo {
public void run() throws OgnlException {
// this uses a null context (2nd parameter), because we have
// a simple hard-coded subtraction expression:
Object result = Ognl.getValue("null - 7", null);
System.out.println(result);
}
}
输出为:-7.0
,与问题中的测试 #2 相同。
致谢
我非常感谢 Thymeleaf 团队为我指明了解决这个问题的正确方向:
Unexpected result from subtraction using nulls
后记
OGNL 表达式:
"1 / null"
计算为 Java 的 Double.POSITIVE_INFINITY
,原因与上述行为相同 - 其中 null
转换为 0.0
。
我有一个 Thymeleaf 模板,没有使用任何 Spring 或 SpEL - 只是 Thymeleaf 标准方言。
模板的相关部分是:
<div>
<span>Inactive: </span>
<span th:text="${total - active}"></span>
</div>
测试 1
如果我的模型填充如下:
model.put("total", 10);
model.put("active", 7);
然后我得到了预期的结果:
<div>
<span>Inactive: </span>
<span>3</span>
</div>
测试 2
但是如果模型值中的一个(或两个)为空:
model.put("total", null);
model.put("active", 7);
然后我得到了意想不到的结果。有了上面的数据,我得到:
<div>
<span>Inactive: </span>
<span>-7.0</span>
</div>
换句话说,null
被计算为浮点数0.0
,因此计算结果为-7.0
。
我原以为它会抛出一个运行时错误,这是由于尝试对空值执行算术而引起的。
测试 3
如果我稍微更改模板并使用与测试 2 相同的数据:
<div>
<span>Inactive: </span>
<span th:text="${total} - ${active}"></span>
</div>
我收到以下运行时错误 - 这是我对测试 2 的预期:
org.thymeleaf.exceptions.TemplateProcessingException: Cannot execute subtraction: operands are "null" and "7"
为什么测试 2 生成了有效的 HTML 而不是抛出错误的计算结果?
(我知道我需要预先处理这些 null
值以避免出现问题,但这种无声的非故障是一个问题。)
快速解答
您应该明确地预先处理 null
值,如问题中所述。
您还应注意 Thymeleaf 的减号运算符与 OGNL 的减号运算符之间的不一致行为。
建议:使用 Thymeleaf 减号运算符。
更详细的解释如下...
Thymeleaf 和 OGNL
当您使用标准 Thymeleaf 方言时,开头 ${
和结尾 }
内的表达式由 OGNL 处理。来自 the official documentation:
This is a variable expression, and it contains an expression in a language called OGNL (Object-Graph Navigation Language) that will be executed on the context variables map...
您可以阅读有关 OGNL 及其语法的信息 here。 Thymeleaf 版本 3.0.12 使用 ognl-3.1.26.jar
库。
因此,当您使用 ${total - active}
时,整个表达式(包括减法)都由 OGNL 处理。
但是,当您使用 ${total} - ${active}
时,这实际上是两个单独的 OGNL 表达式,它们之间有一个减号。
在第一种情况下,执行减法是 OGNL 的责任。但在第二种情况下,减法是由 Thymeleaf 在将两个 ${...}
表达式的评估委托给 OGNL 之后执行的。
Thymeleaf 的大多数运算符通常表现出与 OGNL 相同的行为。但在这种特定情况下,Thymeleaf 减号运算符在处理 null
值时与 OGNL 减号运算符 的行为不同。
我认为 Thymeleaf 行为是不那么令人惊讶的方法。
Spring 和 SpEL
如果您将 Spring 与 Thymeleaf 一起使用,则 ${
和 }
中的所有表达式都将委托给 SpEL(Spring Expression Language)- 并且 OGNL 不会在全部.
在这种情况下,表达式 ${total - active}
将不再在运行时“成功”。相反,它会抛出 SpEL 异常:
org.springframework.expression.spel.SpelEvaluationException: EL1030E: The operator 'SUBTRACT' is not supported between objects of type 'null' and 'java.lang.Integer'
因此,SpEL 和 Thymeleaf 标准方言彼此一致 - 而 OGNL 是少数。
OGNL 真的在这里将 null 评估为零吗?
是的 - 我们可以证明在一个简单的 Java 程序中使用 OGNL:
依赖关系:
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.3.0</version>
<!-- same behavior:
<version>3.2.21</version>
-->
</dependency>
Java演示:
import ognl.Ognl;
import ognl.OgnlException;
public class NullDemo {
public void run() throws OgnlException {
// this uses a null context (2nd parameter), because we have
// a simple hard-coded subtraction expression:
Object result = Ognl.getValue("null - 7", null);
System.out.println(result);
}
}
输出为:-7.0
,与问题中的测试 #2 相同。
致谢
我非常感谢 Thymeleaf 团队为我指明了解决这个问题的正确方向:
Unexpected result from subtraction using nulls
后记
OGNL 表达式:
"1 / null"
计算为 Java 的 Double.POSITIVE_INFINITY
,原因与上述行为相同 - 其中 null
转换为 0.0
。