2.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)。
但您可能还注意到此模板实际上不是有效的 HTML5文档,因为th:*HTML5规范不允许我们在表单中使用这些非标准属性。事实上,我们甚至xmlns:th在我们的<html>标签中添加了一个属性,这绝对不是HTML5-ish:
<html xmlns:th="http://www.thymeleaf.org">
...在模板处理中根本没有任何影响,但作为一个咒语,阻止我们的IDE抱怨缺少所有这些th:*属性的命名空间定义。
那么如果我们想让这个模板HTML5有效呢?简单:切换到Thymeleaf的数据属性语法,使用data-属性名称和hyphen(-)分隔符的前缀而不是分号(:):
<!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>
data-HTML5规范允许使用自定义前缀属性,因此,使用上面的代码,我们的模板将是有效的HTML5文档。
两种表示法都是完全等效且可互换的,但为了代码示例的简单性和紧凑性,本教程将使用名称空间表示法(th:)。此外,th:符号更通用,并且在每个Thymeleaf模板模式(XML,TEXT...)中data-都允许使用,而符号仅在HTML模式下允许。
使用th:文本和外化文本
外化文本是从模板文件中提取模板代码的片段,以便它们可以保存在单独的文件(通常是.properties文件)中,并且可以使用其他语言编写的等效文本(称为国际化或简称为i18n)轻松替换它们。外化的文本片段通常称为“消息”。
消息总是有一个标识它们的键,而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。实现。
标准消息解析程序希望/WEB-INF/templates/home.html在属性文件中查找相同文件夹中的消息,并使用与模板相同的名称,例如:
/WEB-INF/templates/home_en.properties 用于英文文本。
/WEB-INF/templates/home_es.properties 西班牙语文本。
/WEB-INF/templates/home_pt_BR.properties 用于葡萄牙语(巴西)语言文本。
/WEB-INF/templates/home.properties 对于默认文本(如果区域设置不匹配)。
我们来看看我们的home_es.properties文件:
home.welcome=¡Bienvenido a nuestra tienda de comestibles!
这就是我们将Thymeleaf流程作为模板所需的全部内容。让我们创建我们的Home控制器。
上下文
为了处理我们的模板,我们将创建一个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());
}
}
我们看到的第一件事是创建一个上下文。Thymeleaf上下文是实现org.thymeleaf.context.IContext接口的对象。上下文应包含在变量映射中执行模板引擎所需的所有数据,并且还引用必须用于外化消息的语言环境。
public interface IContext {
public Locale getLocale();
public boolean containsVariable(final String name);
public Set<String> getVariableNames();
public Object getVariable(final String name);
}
这个接口有一个专门的扩展,org.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是我们使用的那个。实际上我们必须这样做,因为使用a ServletContextTemplateResolver要求我们使用上下文实现IWebContext。
WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
这四个构造函数参数中只有三个是必需的,因为如果没有指定系统,将使用系统的默认语言环境(尽管在实际应用程序中不应该发生这种情况)。
我们可以使用一些专门的表达式来从WebContext我们的模板中获取请求参数以及请求,会话和应用程序属性。例如:
${x}将返回x存储在Thymeleaf上下文中的变量或作为请求属性。
${param.x}将返回一个被调用的请求参数x(可能是多值的)。
${session.x}将返回一个名为的会话属性x。
${application.x}将返回一个名为的servlet上下文属性x。
执行模板引擎
准备好上下文对象后,现在我们可以告诉模板引擎使用上下文处理模板(通过其名称),并将响应编写器传递给它,以便可以将响应写入它:
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>
网友评论