为了在Spring中使用Tiles,须要配置几个bean。咱们须要一个TilesConfigurer bean,它会负责定位和加载Tile定义并协调生成Tiles。除此以外,还须要TilesViewResolver bean将逻辑视图名称解析为Tile定义。javascript
配置TilesConfigurer来解析Tile定义。php
@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。css
其实咱们还能够指定多个Tile定义文件,甚至可以在路径位置上使用通配符,固然在上例中咱们没有使用该功能。例如,咱们要求TilesConfigurer加载“/WEB-INF/”目录下的全部名字为tiles.xml的文件,那么能够按照以下的方式设置definitions属性:html
tiles.setDefinitons(new String[] { "/WEB-INF/**/tiles.xml" });
让咱们来配置TilesViewResolver,能够看到,这是一个很基本的bean定义,没有什么要设置的属性:java
@Bean public ViewResolver viewResolver(){ return new TilesViewResolver(); }
若是你更喜欢XML配置的话,那么能够按照以下的形式配置TilesConfigurer和TilesViewResolver:web
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles.TilesConfigurer"> <property name="definitions"> <list> <value>/WEB-INF/layout/tiles.xml.xml</value> <value>/WEB-INF/views/**/tiles.xml</value> </list> </property> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.tiles.TilesViewResolver"/>
TilesConfigurer会加载Tile定义并与Apache Tiles协做,而TilesViewRe-solver会将逻辑视图名称解析为引用Tile定义的视图。它是经过查找与逻辑视图名称相匹配的Tile定义实现该功能的。咱们须要建立几个Tile定义以了解它是如何运转的。spring
定义 Tiles
Apache Tiles提供了一个文档类型定义(document type definition,DTD),用来在XML文件中指定Tile的定义。每一个定义中须要包含一个<definition>元素,这个元素会有一个或多个<putattribute>元素。例如,以下的XML文档为 Spittr 应用定义了几个 tile。apache
<?xml version="1.0" encoding="UTF-8" ?> <!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/view/home.jsp"/> </definition> <definition name="registerForm" extends="base"> <put-attribute name="body" value="/WEB-INF/view/registerForm.jsp"/> </definition> <definition name="prefile" 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模板以下面程序清单所示。后端
<%@ 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:uri value="/resource/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所示的布局。数组
如今,咱们关注一下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:uri value="/" />"> <img scr="<s:uri value="/resources"/>/images/spittr_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 Spittr</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模板中再也不包含这部份内容。这使得它们可以跨页面重用,这些元素的维护也得以简化。
JSP 缺点:
JSP缺少良好格式的一个反作用就是它不多可以与其产生的HTML相似。因此,在Web浏览器或HTML编辑器中查看未经渲染的JSP模板是很是使人困惑的,并且获得的结果看上去也很是丑陋。
JSP规范是与Servlet规范紧密耦合的。这意味着它只能用在基于Servlet的Web应用之中。JSP模板不能做为通用的模板(如格式化Email),也不能用于非Servlet的Web应用。
为了要在Spring中使用Thymeleaf,咱们须要配置三个启用Thymeleaf与Spring集成的bean:
-ThymeleafViewResolver:将逻辑视图名称解析为Thymeleaf模板视图;
-SpringTemplateEngine:处理模板并渲染结果;
-TemplateResolver:加载Thymeleaf模板。
以下为声明这些bean的Java配置。
配置Spring对Thymeleaf的支持:
@Bean public viewReslover viewResolver(SpringTemplateEngine templateEngine) { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine); return viewResolver; } @Bean public TemplateEngine templateEngine(TemplateResolver templateResolver) { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); return templateEngine; } @Bean public TemplateReslover templateReslover() { TemplateReslover templateReslover = new ServlteContextTemplateResolver(); templateReslover.setPrefix("/WEB-INF/templates/"); templateReslover.setSuffix(".html"); templateReslover.setTemplate("HTML5"); return templateReslover; }
无论使用哪一种配置方式,Thymeleaf都已经准备就绪了,它能够将响应中的模板渲染到Spring MVC控制器所处理的请求中。
ThymeleafViewResolver是Spring MVC中ViewResolver的一个实现类。像其余的视图解析器同样,它会接受一个逻辑视图名称,并将其解析为视图。不过在该场景下,视图会是一个Thymeleaf模板。
须要注意的是ThymeleafViewResolver bean中注入了一个对SpringTemplate Engine bean的引用。SpringTemplateEngine会在Spring中启用Thymeleaf引擎,用来解析模板,并基于这些模板渲染结果。能够看到,咱们为其注入了一个TemplateResolver bean的引用。
TemplateResolver会最终定位和查找模板。与以前配置InternalResource-ViewResolver相似,它使用了prefix和suffix属性。前缀和后缀将会与逻辑视图名组合使用,进而定位Thymeleaf引擎。它的templateMode属性被设置成了HTML 5,这代表咱们预期要解析的模板会渲染成HTML 5输出。
全部的Thymeleaf bean都已经配置完成了,那么接下来咱们该建立几个视图了。
使用Thymeleaf命名空间的首页模板引擎:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.thymeleaf.org"> <link> <title>Spittr</title> <link rel="stylesheet" type="/text/css" th:href="@{/resources/style.css}"></link> </head> <body> <h1>Welcome to Spittr</h1> <a th:href="@{/spittles}">Spittles</a> <a th:href="@{/spitter/register}">Register</a> </body> </html>
首页模板相对来说很简单,只使用了th:href属性。这个属性与对应的原生HTML属性很相似,也就是href属性,而且能够按照相同的方式来使用。th:href属性的特殊之处在于它的值中能够包含Thymeleaf表达式,用来计算动态的值。它会渲染成一个标准的href属性,其中会包含在渲染时动态建立获得的值。这是Thymeleaf命名空间中不少属性的运行方式:它们对应标准的HTML属性,而且具备相同的名称,可是会渲染一些计算后获得的值。在本例中,使用th:href属性的三个地方都用到了“@{}”表达式,用来计算相对于URL的路径(就像在JSP页面中,咱们可能会使用的JSTL <c:url>标签或Spring<s:url>标签相似)。
表单绑定是Spring MVC的一项重要特性。它可以将表单提交的数据填充到命令对象中,并将其传递给控制器,而在展示表单的时候,表单中也会填充命令对象中的值。若是没有表单绑定功能的话,咱们须要确保HTML表单域要映射后端命令对象中的属性,而且在校验失败后展示表单的时候,还要负责确保输入域中值要设置为命令对象的属性。可是,若是有表单绑定的话,它就会负责这些事情了。
请参考以下的Thymeleaf模板片断,它会渲染FirstName输入域:
<label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label> <input type="text" th:field="*{fileName}" th:class="${#fields.hasErrors('firstName')}? 'error'"/><br/>
th:class属性会渲染为一个class属性,它的值是根据给定的表达式计算获得的。在上面的这两个th:class属性中,它会直接检查firstName域有没有校验错误。若是有的话,class属性在渲染时的值为error。若是这个域没有错误的话,将不会渲染class属性。