【问题标题】:Unexpected result using Thymeleaf arithmetic使用 Thymeleaf 算术的意外结果
【发布时间】:2021-12-02 09:50:44
【问题描述】:

我有一个 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:无法执行减法:操作数为“null”和“7”

为什么测试 2 会生成具有意外计算结果的有效 HTML,而不是抛出错误?

(我知道我需要预先处理这些 null 值以避免出现问题,但是这种无声的非失败是一个问题。)

【问题讨论】:

    标签: java html thymeleaf ognl


    【解决方案1】:

    快速解答

    您应该提前明确处理 null 值,如问题中所述。

    您还应该注意 Thymeleaf 的减号运算符和 OGNL 的减号运算符之间的不一致行为。

    建议:使用 Thymeleaf 减号运算符。

    下面有更详细的解释...

    Thymeleaf 和 OGNL

    当您使用标准 Thymeleaf 方言时,开头 ${ 和结尾 } 中的表达式由 OGNL 处理。来自the official documentation

    这是一个变量表达式,它包含一个名为 OGNL(Object-Graph Navigation Language)语言的表达式,它将在上下文变量映射上执行...

    您可以阅读有关 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: 在“null”和“java.lang.Integer”类型的对象之间不支持运算符“SUBTRACT”

    所以,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

    【讨论】:

      猜你喜欢
      • 2019-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-11
      • 2014-12-01
      • 1970-01-01
      • 2018-04-25
      • 1970-01-01
      相关资源
      最近更新 更多