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>