爲了在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屬性。