Spring 學習筆記(十)渲染 Web 視圖 (Apache Tilesa 和 Thymeleaf)

使用Apache Tiles視圖定義佈局

爲了在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所示的佈局。數組


 
image.png

如今,咱們關注一下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 &copy; 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模板中再也不包含這部份內容。這使得它們可以跨頁面重用,這些元素的維護也得以簡化。

使用Thymeleaf

JSP 缺點:
JSP缺少良好格式的一個反作用就是它不多可以與其產生的HTML相似。因此,在Web瀏覽器或HTML編輯器中查看未經渲染的JSP模板是很是使人困惑的,並且獲得的結果看上去也很是醜陋。
JSP規範是與Servlet規範緊密耦合的。這意味着它只能用在基於Servlet的Web應用之中。JSP模板不能做爲通用的模板(如格式化Email),也不能用於非Servlet的Web應用。

配置Thymeleaf視圖解析器

爲了要在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模板

使用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>標籤相似)。

藉助Thymeleaf實現表單綁定

表單綁定是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屬性。

做者:theodore的技術提高之路 連接:https://www.jianshu.com/p/03fa32a3a1f4 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
相關文章
相關標籤/搜索