Skip to content

4.2 变量表达式

我们此前提到过,${...} 表达式本质上是OGNL(对象图导航语言,Object-Graph Navigation Language) 表达式,会在上下文包含的变量映射表中执行。

INFO

关于 OGNL 语法和特性的详细信息,可参考《OGNL 语言指南》(OGNL Language Guide)。

注:在启用 Spring MVC 的应用中,OGNL 会被 SpringEL(Spring 表达式语言)替代,但二者语法高度相似(事实上,绝大多数常用场景下语法完全一致)。

从 OGNL 语法规则来看,这段代码中的表达式:

html
<p>Today is: <span th:text="${today}">13 february 2011</span>.</p>

其实等价于执行:

java
ctx.getVariable("today");

但 OGNL 能支持更强大的表达式,比如下面这段代码:

html
<p th:utext="#{home.welcome(${session.user.name})}">
  Welcome to our grocery store, Sebastian Pepper!
</p>

之所以能获取到用户名,是因为它底层执行了:

java
((User) ctx.getVariable("session").get("user")).getName();

不过,通过 getter 方法导航只是 OGNL 的特性之一。我们再看几个常用用法:

thymeleaf
/*
 * 1. 点号(.)访问属性:等价于调用属性的 getter 方法
 */
${person.father.name}

/*
 * 2. 方括号([])访问属性:
 *    可将属性名作为变量,或用单引号包裹属性名
 */
${person['father']['name']}

/*
 * 3. 若对象是 Map:
 *    点号和方括号语法均等价于调用 Map 的 get(...) 方法
 */
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}

/*
 * 4. 数组/集合的索引访问:
 *    方括号内写数字索引(无需引号)
 */
${personsArray[0].name}

/*
 * 5. 方法调用:支持无参/带参调用
 */
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}

核心语法解释

  1. OGNL 导航的核心逻辑
    • 点号(.)是最常用的语法,本质是调用 Java 对象的 getter 方法(如 ${person.name} 等价于 person.getName());
    • 方括号([])是通用访问语法,既可以访问对象属性,也可以访问 Map 的键、数组/集合的索引,灵活性更高。
  2. Map 访问的特殊性${countriesByCode.ES} 中,ES 是 Map 的键,等价于 countriesByCode.get("ES");而 ${personsByName['Stephen Zucchini']} 则是通过字符串键访问 Map 中的对象。
  3. 方法调用的实用性: 支持直接调用对象的方法(如 ${person.createCompleteName('-')}),无需在控制器中提前处理数据,可直接在模板中完成简单的业务逻辑。
  4. SpringEL 兼容说明: 若使用 Spring MVC,上述语法几乎无需修改(如 ${person.name}${map.key}、方法调用等),仅底层执行引擎从 OGNL 换成 SpringEL,对开发者透明。

总结

  1. ${...} 变量表达式基于 OGNL/SpringEL 实现,核心是“对象图导航”,支持通过点号/方括号访问属性、Map、数组/集合,也支持直接调用方法。
  2. 方括号语法比点号更灵活,可处理属性名含特殊字符、动态属性名等场景;点号语法更简洁,适合常规属性访问。
  3. Spring 环境下 OGNL 自动替换为 SpringEL,语法基本兼容,无需额外学习成本。