三、使用 Literals
3.1 多国语言欢迎
我们的首要任务是为我们的杂货店网站创建主页。
该页面的第一个版本非常简单:只有标题和欢迎消息。这是我们的/WEB-INF/templates/home.html
文件:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
</body>
</html>
您会注意到的第一件事是该文件是 HTML5,任何浏览器都可以正确显示该文件,因为它不包含任何非 HTML 标记(浏览器会忽略他们不了解的所有属性,例如th:text
)。
但您可能还会注意到,此模板并不是 true 的有效 HTML5 文档,因为 HTML5 规范不允许我们以th:*
形式使用的这些非标准属性。实际上,我们甚至在<html>
标记中添加了xmlns:th
属性,这绝对不符合 HTML5 规范:
<html xmlns:th="http://www.thymeleaf.org">
…这在模板处理中完全没有影响,但是起“引诱”作用,可防止我们的 IDE 抱怨所有th:*
属性缺少名称空间定义。
那么,如果我们想使此模板成为 HTML5-valid **怎么办?简单:使用属性名称和连字符(-
)分隔符而不是分号(:
)的前缀data-
切换到 Thymeleaf 的数据属性语法:
<!DOCTYPE html>
<html>
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" data-th-href="@{/css/gtvg.css}" />
</head>
<body>
<p data-th-text="#{home.welcome}">Welcome to our grocery store!</p>
</body>
</html>
HTML5 规范允许使用自定义data-
前缀的属性,因此,使用上面的代码,我们的模板将是有效的 HTML5 文档。
这两种符号是完全等效且可互换的,但是为了代码示例的简洁和紧凑,本教程将使用命名空间符号(
th:*
)。同样,th:*
表示法更通用,并且在每种 Thymeleaf 模板模式(XML
,TEXT
…)中都允许使用,而data-
表示法仅在HTML
模式中允许使用。
使用 th:text 和外部化文本
外部化文本是从模板文件中提取模板代码的片段,以便可以将其保存在单独的文件(通常为.properties
文件)中,并可以用其他语言编写的等效文本轻松替换它们(此过程称为国际化或简称为* i18n * )。文本的外部化片段通常称为*“ messages” *。
消息始终具有用于标识消息的密钥,Thymeleaf 允许您使用#{...}
语法指定文本应与特定消息相对应:
<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
我们在这里看到的实际上是 Thymeleaf 标准方言的两个不同功能:
th:text
属性用于评估其值表达式并将结果设置为主机标签的正文,从而有效地替代了“欢迎来到我们的杂货店!”我们在代码中看到的文本。- 在“标准表达式语法”中指定的
#{home.welcome}
表达式指示th:text
属性要使用的文本应该是带有home.welcome
键的消息,该消息对应于我们处理模板所使用的任何语言环境。
现在,此外部化文本在哪里?
Thymeleaf 中外部化文本的位置是完全可配置的,并且将取决于所使用的特定org.thymeleaf.messageresolver.IMessageResolver
实现。通常,将使用基于.properties
文件的实现,但是如果我们想从数据库中获取消息,则可以创建自己的实现。
但是,我们没有在初始化期间为模板引擎指定消息解析器,这意味着我们的应用程序正在使用由org.thymeleaf.messageresolver.StandardMessageResolver
实现的* Standard Message Resolver *。
标准消息解析器希望在与文件夹相同名称和模板名称的属性文件中找到/WEB-INF/templates/home.html
的消息,例如:
/WEB-INF/templates/home_en.properties
用于英文文本。/WEB-INF/templates/home_es.properties
用于西班牙语文本。/WEB-INF/templates/home_pt_BR.properties
用于葡萄牙语(巴西)语言 Literals。/WEB-INF/templates/home.properties
用于默认文本(如果语言环境不匹配)。
我们来看一下home_es.properties
文件:
home.welcome=¡Bienvenido a nuestra tienda de comestibles!
这就是使 Thymeleaf 加工成为模板所需要的。然后创建我们的 Home 控制器。
Contexts
为了处理我们的模板,我们将创建一个HomeController
类,以实现我们之前看到的IGTVGController
接口:
public class HomeController implements IGTVGController {
public void process(
final HttpServletRequest request, final HttpServletResponse response,
final ServletContext servletContext, final ITemplateEngine templateEngine)
throws Exception {
WebContext ctx =
new WebContext(request, response, servletContext, request.getLocale());
templateEngine.process("home", ctx, response.getWriter());
}
}
我们看到的第一件事是创建* context *。 Thymeleaf 上下文是实现org.thymeleaf.context.IContext
接口的对象。上下文应在变量 Map 中包含执行模板引擎所需的所有数据,并且还应引用必须用于外部化消息的语言环境。
public interface IContext {
public Locale getLocale();
public boolean containsVariable(final String name);
public Set<String> getVariableNames();
public Object getVariable(final String name);
}
该接口有一个专门的 extensionsorg.thymeleaf.context.IWebContext
,旨在用于基于 ServletAPI 的 Web 应用程序(如 SpringMVC)。
public interface IWebContext extends IContext {
public HttpServletRequest getRequest();
public HttpServletResponse getResponse();
public HttpSession getSession();
public ServletContext getServletContext();
}
Thymeleaf 核心库提供了以下每个接口的实现:
org.thymeleaf.context.Context
实施IContext
org.thymeleaf.context.WebContext
实施IWebContext
正如您在控制器代码中看到的那样,WebContext
是我们使用的那个。实际上,我们必须这样做,因为使用ServletContextTemplateResolver
要求我们使用实现IWebContext
的上下文。
WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
这四个构造函数参数中只有三个是必需的,因为如果未指定默认语言环境,则将使用系统的默认语言环境(尽管您绝对不应在实际应用程序中让这种情况发生)。
我们可以使用一些专门的表达式从模板中的WebContext
获取请求参数以及请求,会话和应用程序属性。例如:
${x}
将返回存储在 Thymeleaf 上下文中或作为* request 属性*的变量x
。${param.x}
将返回一个称为x
的请求参数(可能是多值)。${session.x}
将返回名为x
的会话属性。${application.x}
将返回名为x
的* servlet 上下文属性*。
执行模板引擎
准备好上下文对象后,现在我们可以告诉模板引擎使用上下文处理模板(按其名称),并将其传递给响应编写器,以便可以将响应写入其中:
templateEngine.process("home", ctx, response.getWriter());
让我们使用西班牙语语言环境查看结果:
<!DOCTYPE html>
<html>
<head>
<title>Good Thymes Virtual Grocery</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<link rel="stylesheet" type="text/css" media="all" href="/gtvg/css/gtvg.css" />
</head>
<body>
<p>¡Bienvenido a nuestra tienda de comestibles!</p>
</body>
</html>
3.2 有关文本和变量的更多信息
Unescaped Text
主页的最简单版本现在似乎已经准备就绪,但是有些事情我们还没有想到……如果我们收到这样的消息怎么办?
home.welcome=Welcome to our <b>fantastic</b> grocery store!
如果我们像以前一样执行此模板,我们将获得:
<p>Welcome to our <b>fantastic</b> grocery store!</p>
这并不完全符合我们的预期,因为我们的<b>
标记已转义,因此将显示在浏览器中。
这是th:text
属性的默认行为。如果我们希望 Thymeleaf 尊重我们的 HTML 标记而不是对其进行转义,则必须使用不同的属性:th:utext
(用于“未转义的文本”):
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
这将输出我们的消息,就像我们想要的那样:
<p>Welcome to our <b>fantastic</b> grocery store!</p>
使用和显示变量
现在,让我们向主页添加更多内容。例如,我们可能希望在欢迎消息下方显示日期,如下所示:
Welcome to our fantastic grocery store!
Today is: 12 july 2010
首先,我们将必须修改控制器,以便我们将该日期添加为上下文变量:
public void process(
final HttpServletRequest request, final HttpServletResponse response,
final ServletContext servletContext, final ITemplateEngine templateEngine)
throws Exception {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
Calendar cal = Calendar.getInstance();
WebContext ctx =
new WebContext(request, response, servletContext, request.getLocale());
ctx.setVariable("today", dateFormat.format(cal.getTime()));
templateEngine.process("home", ctx, response.getWriter());
}
我们在上下文中添加了一个名为String
的String
变量,现在可以在模板中显示它了:
<body>
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
<p>Today is: <span th:text="${today}">13 February 2011</span></p>
</body>
如您所见,我们仍在为工作使用th:text
属性(这是正确的,因为我们要替换标签的正文),但是这次的语法有所不同,而不是#{...}
表达式值,使用一个${...}
。这是一个“变量表达式”,它包含一个名为* OGNL(对象图导航语言)*的语言,该表达式将在我们之前谈到的上下文变量 Map 上执行。
${today}
表达式仅表示“获取今天的变量”,但这些表达式可能更复杂(例如${user.name}
表示“获取用户的变量,并调用其getName()
方法”)。
属性值有很多可能性:消息,变量表达式等等。下一章将向我们展示所有这些可能性。
最新评论
Spring Cloud Alibaba 微服务架构实战 https://pan.baidu.com/s/1jF5voFRoeF0lYAzAPBWSbw?pwd=chqk
命令: nload
真是个良心站点哇,大公无私,爱了爱了
还可以直接搞一张映射表,存 uid | time | source_index, 第一次直接查对应的 time 选出前100, 第二次直接用 CompleteFuture 去分别用 source_in
干得漂亮,多个朋友堵条路
2021.2.2版本的不适用吧
现在还可以用么
激活码有用,感谢分享