开发学院

您的位置:首页>教程>正文

教程正文

Thymeleaf 3.0教程:4 标准表达式语法(1)

  我们将在杂货店虚拟商店的开发中稍作休息,学习Thymeleaf标准方言最重要的部分之一:Thymeleaf标准表达式语法。

  我们已经看到两种类型的有效属性值用这种语法表示:消息和变量表达式:

<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
<p>Today is: <span th:text="${today}">13 february 2011</span></p>

  但是有更多类型的表达式,和更多有趣的细节需要我们来了解。首先,让我们快速总结一下标准表达式的功能:

简单的表达:

Variable Expressions: ${...}
Selection Variable Expressions: *{...}
Message Expressions: #{...}
Link URL Expressions: @{...}
Fragment Expressions: ~{...}

文字

Text literals: 'one text', 'Another one!',…
Number literals: 0, 34, 3.0, 12.3,…
Boolean literals: true, false
Null literal: null
Literal tokens: one, sometext, main,…

文本操作:

String concatenation: +
Literal substitutions: |The name is ${name}|

算术运算:

Binary operators: +, -, *, /, %
Minus sign (unary operator): -

布尔运算:

Binary operators: and, or
Boolean negation (unary operator): !, not

比较运算:

Comparators: >, <, >=, <= (gt, lt, ge, le)
Equality operators: ==, != (eq, ne)

条件运算符:

If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)

特殊令牌:

No-Operation: _

  所有这些功能都可以组合和嵌套:

'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

4.1 消息

  我们已经知道,#{...}消息表达式允许我们输出文本消息:

<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>

  文本来源:

home.welcome=¡Bienvenido a nuestra tienda de comestibles!

  但是有一个方面我们还没有想到:如果消息文本不是完全静态的,会发生什么?例如,如果我们的应用程序知道在任何时候谁是访问该网站的用户,并且我们想用名字问候他们,该怎么办?

<p>¡Bienvenido a nuestra tienda de comestibles, John Apricot!</p>

  这意味着我们需要在消息中添加一个参数。就像这样:

home.welcome=¡Bienvenido a nuestra tienda de comestibles, {0}!

  参数是根据java.text.MessageFormat标准语法指定的,这意味着您可以将java.text.*包中的类格式化为API文档中指定的数字和日期。

  为了给我们的参数指定一个值,并指定一个名为user的会话属性,我们可以:

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

  请注意,这里使用th:utext意味着格式化的消息不会被转义。本示例假设用户名已经转义。

  可以指定几个参数,用逗号分隔。

  消息本身可以来自一个变量:

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

4.2 变量

  我们已经提到${...}表达式实际上是在上下文中包含的变量映射上执行的OGNL表达式。

  有关OGNL语法和功能的详细信息,可以阅读《OGNL语言指南》

  在支持Spring MVC的应用程序中,OGNL将被SpringEL所取代,但是它的语法与OGNL非常相似(实际上,对于大多数常见的情况来说完全相同)。

  从OGNL的语法中,我们知道表达式在:

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

  事实上相当于:

ctx.getVariable("today");

  但是OGNL允许我们创造更强大的表达式,这就是为什么:

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

  通过执行以下操作获取用户名:

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

  但是getter方法导航只是OGNL的特色之一。让我们看更多:

/*
 * Access to properties using the point (.). Equivalent to calling property getters.
 */
${person.father.name}

/*
 * Access to properties can also be made by using brackets ([]) and writing 
 * the name of the property as a variable or between single quotes.
 */
${person['father']['name']}

/*
 * If the object is a map, both dot and bracket syntax will be equivalent to 
 * executing a call on its get(...) method.
 */
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}

/*
 * Indexed access to arrays or collections is also performed with brackets, 
 * writing the index without quotes.
 */
${personsArray[0].name}

/*
 * Methods can be called, even with arguments.
 */
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}

表达式基本对象

  在上下文变量上评估OGNL表达式时,一些对象可用于表达式以获得更高的灵活性。这些对象将以#符号开始引用(根据OGNL标准):

#ctx: the context object.
#vars: the context variables.
#locale: the context locale.
#request: (only in Web Contexts) the HttpServletRequest object.
#response: (only in Web Contexts) the HttpServletResponse object.
#session: (only in Web Contexts) the HttpSession object.
#servletContext: (only in Web Contexts) the ServletContext object.

  所以我们可以这样做:

Established locale country: <span th:text="${#locale.country}">US</span>.

  你可以在附录中读到这些对象的参考资料。

表达式实用程序对象

  除了这些基本对象,百里香叶还将为我们提供一组实用对象,帮助我们在表达式中执行常见任务。

#execInfo: information about the template being processed.
#messages: methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris: methods for escaping parts of URLs/URIs
#conversions: methods for executing the configured conversion service (if any).
#dates: methods for java.util.Date objects: formatting, component extraction, etc.
#calendars: analogous to #dates, but for java.util.Calendar objects.
#numbers: methods for formatting numeric objects.
#strings: methods for String objects: contains, startsWith, prepending/appending, etc.
#objects: methods for objects in general.
#bools: methods for boolean evaluation.
#arrays: methods for arrays.
#lists: methods for lists.
#sets: methods for sets.
#maps: methods for maps.
#aggregates: methods for creating aggregates on arrays or collections.
#ids: methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).

  您可以在附录b中检查这些实用程序对象中的每一个提供了什么功能。

在我们的主页上重新格式化日期

  现在我们了解了这些实用程序对象,我们可以用它们来改变我们在主页上显示日期的方式。不是在我们的家庭控制器中这样做:

SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
Calendar cal = Calendar.getInstance();

WebContext ctx = new WebContext(request, servletContext, request.getLocale());
ctx.setVariable("today", dateFormat.format(cal.getTime()));

templateEngine.process("home", ctx, response.getWriter());

  我们可以做到这一点:

WebContext ctx = 
    new WebContext(request, response, servletContext, request.getLocale());
ctx.setVariable("today", Calendar.getInstance());

templateEngine.process("home", ctx, response.getWriter());

  然后在视图层本身中执行日期格式化:

<p>
  Today is: <span th:text="${#calendars.format(today,'dd MMMM yyyy')}">13 May 2011</span>
</p>