为了在 Spring 中使用 Tiles,需要配置几个 bean。我们需要一个 TilesConfigurer bean,它会负责定位和加载 Tile 定义并协调生成 Tiles。除此之外,还需要 TilesViewResolver bean 将逻辑视图名称解析为 Tile 定义。
这两个组件又有两种形式:针对 Apache Tiles 2 和 Apache Tiles 3 分别都有这么两个组件。这两组 Tiles 组件之间最为明显的区别在于包名。针对 Apache Tiles 2 的 TilesConfigurer/TilesViewResolver 位于 org.springframework.web .servlet.view.tiles2 包中,而针对 Tiles 3 的组件位于 org.springframework .web.servlet.view.tiles3包中。对于该例子来讲,假设我们使用的Tiles 3。
首先,配置 TilesConfigurer 来解析 Tile 定义。
程序清单 6.1 配置 TilesConfigurer 来解析定义
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tiles = new TilesConfigurer();
tiles.setDefinitions(new String[] {
"/WEB-INF/layout/tiles.xml"
});
tiles.setCheckRefresh(true);
return tiles;
}
当配置 TilesConfigurer 的时候,所要设置的最重要的属性就是 definitions。这个属性接受一个 String 类型的数组,其中每个条目都指定一个 Tile 定义的 XML 文件。对于 Spittr 应用来讲,我们让它在 /WEB-INF/layout/
目录下查找 tiles.xml。
其实我们还可以指定多个 Tile 定义文件,甚至能够在路径位置上使用通配符,当然在上例中我们没有使用该功能。例如,我们要求 TilesConfigurer 加载 /WEB-INF/
目录下的所有名字为 tiles.xml 的文件,那么可以按照如下的方式设置 definitions 属性:
tiles.setDefinitions(new String[] {
"/WEB-INF/**/tiles.xml"
});
在本例中,我们使用了 Ant 风格的通配符 **
,所以 TilesConfigurer 会遍历 WEB-INF/
的所有子目录来查找 Tile 定义。
接下来,让我们来配置 TilesViewResolver,可以看到,这是一个很基本的 bean 定义,没有什么要设置的属性:
@Bean
public ViewResolver viewResolver() {
return new TilesViewResolver();
}
如果你更喜欢 XML 配置的话,那么可以按照如下的形式配置 TilesConfigurer 和 TilesViewResolver:
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layout/tiles.xml.xml</value>
<value>/WEB-INF/**/tiles.xml</value>
</list>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.tiles3.TilesViewResolver" />
TilesConfigurer 会加载 Tile 定义并与 Apache Tiles 协作, 而 TilesView-Resolver 会将逻辑视图名称解析为引用 Tile 定义的视图。它是通过查找与逻辑视图名称相匹配的 Tile 定义实现该功能的。我们需要创建几个 Tile 定义以了解它是如何运转的。
定义 Tiles Apache
Tiles 提供了一个文档类型定义(document type definition,DTD),用来在 XML 文件中指定 Tile 的定义。每个定义中需要包含一个元素,这个元素会有一个或多个元素。例如,如下的 XML 文档为 Spittr 应用定义了几个 Tile。
程序清单 6.2 为 Spittr 应用定义 Tile
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="base" template="/WEB-INF/layout/page.jsp">
<put-attribute name="header" value="/WEB-INF/layout/header.jsp" />
<put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />
</definition>
<definition name="home" extends="base">
<put-attribute name="body" value="/WEB-INF/views/home.jsp" />
</definition>
<definition name="registerForm" extends="base">
<put-attribute name="body" value="/WEB-INF/views/registerForm.jsp" />
</definition>
<definition name="profile" extends="base">
<put-attribute name="body" value="/WEB-INF/views/profile.jsp" />
</definition>
<definition name="spittles" extends="base">
<put-attribute name="body" value="/WEB-INF/views/spittles.jsp" />
</definition>
<definition name="spittle" extends="base">
<put-attribute name="body" value="/WEB-INF/views/spittle.jsp" />
</definition>
</tiles-definitions>
每个 <definition>
元素都定义了一个 Tile,它最终引用的是一个 JSP 模板。在名为 base 的 Tile 中,模板引用的是 /WEBINF/ layout/page.jsp
。某个 Tile 可能还会引用其他的 JSP 模板,使这些 JSP 模板嵌入到主模板中。对于 base Tile 来讲,它引用的是一个头部 JSP 模板和一个底部 JSP 模板。
base Tile 所引用的 page.jsp 模板如下面程序清单所示。
程序清单 6.3 主布局模板:引用其他模板来创建视图
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %>
<%@ page session="false" %>
<html>
<head>
<title>Spittr</title>
<link rel="stylesheet"
type="text/css"
href="<s:url value="/resources/style.css" />" >
</head>
<body>
<div id="header">
<t:insertAttribute name="header" />
</div>
<div id="content">
<t:insertAttribute name="body" />
</div>
<div id="footer">
<t:insertAttribute name="footer" />
</div>
</body>
</html>
在程序清单 6.3 中,需要重点关注的事情就是如何使用 Tile 标签库中的 <t:insert Attribute>
JSP 标签来插入其他的模板。在这里,用它来插入名为 header、body 和 footer 的模板。最终,它会形成图 6.4 所示的布局。
在 base Tile 定义中,header 和 footer 属性分别被设置为引用 /WEB-INF/ layout/header.jsp
和 /WEB-INF/layout/footer.jsp
。但是 body 属性呢?它是在哪里设置的呢?
在这里,base Tile 不会期望单独使用。它会作为基础定义(这是其名字的来历),供其他的 Tile 定义扩展。在程序清单 6.2 的其余内容中,我们可以看到其他的 Tile 定义都是扩展自 base Tile。它意味着它们会继承其 header 和 footer 属性的设置(当然,Tile 定义中也可以覆盖掉这些属性),但是每一个都设置了 body 属性,用来指定每个 Tile 特有的 JSP 模板。
现在,我们关注一下 home Tile,它扩展了 base。因为它扩展了 base,因此它会继承 base 中的模板和所有的属性。尽管 home Tile 定义相对来说很简单,但是它实际上包含了如下的定义:
<definition name="home" template="/WEB-INF/layout/page.jsp">
<put-attribute name="header" value="/WEB-INF/layout/header.jsp" />
<put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />
<put-attribute name="body" value="/WEB-INF/views/home.jsp" />
</definition>
属性所引用的每个模板是很简单的,如下是 header.jsp 模板:
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<a href="<s:url value="/" />"><img
src="<s:url value="/resources" />/images/spitter_logo_50.png"
border="0"/></a>
footer.jsp 模板更为简单:
Copyright © Craig Walls
每个扩展自 base 的 Tile 都定义了自己的主体区模板,所以每个都会与其他的有所区别。但是为了完整地了解 home Tile,如下展现了 home.jsp:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<h1>Welcome to Spitter</h1>
<a href="<c:url value="/spittles" />">Spittles</a> |
<a href="<c:url value="/spitter/register" />">Register</a>
这里的关键点在于通用的元素放到了 page.jsp、header.jsp 以及 footer.jsp 中,其他的 Tile 模板中不再包含这部分内容。这使得它们能够跨页面重用,这些元素的维护也得以简化。
要想看一下这些元素组合在一起的样子,那么可以看一下图 6.5。如图所示,它包含了一些样式和图像以增加应用的美观性。我们不是专门讨论使用 Tiles 实现页面布局的,因此在本节中不会涵盖所有的细节。但是,我们可以看到页面上的各种组件通过 Tile 定义组合在了一起,并且渲染出了 Spittr 应用的主页。
在 Java Web 应用领域,JSP 长期以来都是占据主导地位的方案。但是,在这个领域有了新的竞争者,也就是 Thymeleaf。接下来让我们 看一下如何在 Spring MVC 应用中使用 Thymeleaf。