Spring MVC視圖層:thymeleaf vs. JSP

jopen 10年前發布 | 23K 次閱讀 Java開發

本文對比了同一Spring MVC工程中相同頁面(一個訂閱表單)分別采用Thymeleaf和JSP(包括JSP、JSTL、Spring tag lib)兩種方式的實現。

本文的所有代碼來自一個可運行的應用。你可以從文檔頁面下載該應用程序的源代碼。

Common requirements

顧客通過一個表單添加到消息列表中,包含下面兩個域:

  • Email地址
  • 訂閱類型(接收所有郵件、每日摘要)

要求該頁面支持HTML5且完全國際化,國際化信息從Spring框架中配置的MessageSource對象中抽取所有的文本和消息。

該應用包含兩個@Controller,二者含有相同的代碼,只是跳轉到不同的view:

  • SubscribeJsp用于JSP頁面(subscribejsp視圖)
  • SubscribeTh用于Thymeleaf頁面(subscribeth視圖)

在模型(model)中包含下列類:

  • Subscription:form-backing bean,包含兩個域:String email和SubscriptionType subscriptionType。
  • SubscriptionType:一個枚舉類型,表單中subscriptionType域的值,可取的值包含ALL_EMAILS和DAILY_DIGEST。

(本文我們僅關注JSP和Thymeleaf模板代碼的討論。如果你想了解controller代碼和Spring配置的實現細節,請自行查看下載包中的源代碼)

使用JSP實現(Doing it with JSP)

這是頁面:


下面是JSP代碼,使用了JSTL(core)和Spring(tags和form) JSP標簽庫:

<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %><%@
taglib prefix="s" uri="http://www.springframework.org/tags" %><%@
taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@
page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html>

<html>

<head>
    <title>Spring MVC view layer: Thymeleaf vs. JSP</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" media="all" href="<s:url value='/css/thvsjsp.css' />"/>
</head>

<body>

<h2>This is a JSP</h2>

<s:url var="formUrl" value="/subscribejsp" />
<sf:form modelAttribute="subscription" action="${formUrl}">

    <fieldset>

        <div>
            <label for="email"><s:message code="subscription.email" />: </label>
            <sf:input path="email" />
        </div>
        <div>
            <label><s:message code="subscription.type" />: </label>
            <ul>
                <c:forEach var="type" items="${allTypes}" varStatus="typeStatus">
                    <li>
                        <sf:radiobutton path="subscriptionType" value="${type}" />
                        <label for="subscriptionType${typeStatus.count}">
                            <s:message code="subscriptionType.${type}" />
                        </label>
                    </li>
                </c:forEach>
            </ul>
        </div>

        <div class="submit">
            <button type="submit" name="save"><s:message code="subscription.submit" /></button>
        </div>

    </fieldset>

</sf:form>

</body>

</html>


使用Thymeleaf實現(Doing it with Thymeleaf)

下面使用Thymeleaf實現相同的頁面。頁面如下:


下面是Thymeleaf代碼:

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head>
    <title>Spring MVC view layer: Thymeleaf vs. JSP</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" media="all"
          href="../../css/thvsjsp.css" th:href="@{/css/thvsjsp.css}"/>
</head>

<body>

<h2>This is a Thymeleaf template</h2>

<form action="#" th:object="${subscription}" th:action="@{/subscribeth}">

    <fieldset>

        <div>
            <label for="email" th:text="#{subscription.email}">Email: </label>
            <input type="text" th:field="*{email}" />
        </div>
        <div>
            <label th:text="#{subscription.type}">Type: </label>
            <ul>
                <li th:each="type : ${allTypes}">
                    <input type="radio" th:field="*{subscriptionType}" th:value="${type}" />
                    <label th:for="${#ids.prev('subscriptionType')}"
                           th:text="#{'subscriptionType.'+${type}}">First type</label>
                </li>
                <li th:remove="all"><input type="radio" /> <label>Second Type</label></li>
            </ul>
        </div>

        <div class="submit">
            <button type="submit" name="save" th:text="#{subscription.submit}">Subscribe me!</button>
        </div>

    </fieldset>

</form>

</body>

</html>

注意事項:

  • 上述代碼更加接近HTML——沒有奇怪的標簽,只是增加了一些有意義的屬性。
  • 變量表達式(${...})是Spring EL且在模型屬性(model attributes)上執行,星號表達式(*{...})在form backing bean上執行,hash表達式(#{...})用于國際化,link表達式(@{...})重寫URL。(如果想深入學習,參考Getting started with the Standard Dialect in 5 minutes)。
  • 這里允許使用原型代碼(prototype code):例如,可以把第一個域的標簽設置為Email:,而在頁面執行時,Thymeleaf會根據subscription.email的值把它替換為國際化的文本。
  • 我們甚至可以添加一個<li>僅僅用于prototype。當Thymeleaf執行頁面時將會被刪掉。

改變頁面風格(Let's change the page style)

假象我們寫完了頁面,但是我們突然想改變一下按鈕周圍的顏色:從綠色改為淡藍色。我們不確定那種藍色更加合適,因此我們需要多次嘗試不同的顏色組合。

下面看一下采用JSP和Thymeleaf的實現方式:

采用JSP修改頁面風格(Changing the page style using JSP)

第1步:將應用程序部署到開發服務器上,并啟動服務器。如果服務器不啟動,JSP頁面不會渲染,因此這一步是必須的。

第2步:導航到需要修改的頁面。通常情況下,需要修改的頁面是該應用程序的所有頁面中某一個,很有可能需要點擊多個鏈接、提交多個表單、查詢多次數據庫后才能跳轉到這個頁面。

第3步:打開firebug、dragonfly或其他嵌入瀏覽器的web開發工具。通過這些工具我們可以修改頁面風格,并直接作用到瀏覽器的DOM上,并顯示給我們。

第4步:修改顏色。嘗試多種顏色組合后,確定最合適的顏色。


第5步:復制修改過的代碼,并粘貼到對應的CSS文件中。

完成!

采用Thymeleaf修改頁面風格(Changing the page style using Thymeleaf)

第1步:雙擊.html模板文件,在瀏覽器中打開它。由于是Thymeleaf模板,它將會正常顯示,采用模板/原型(template/prototype)數據(注意訂閱類型選項):


第2步:使用文本編輯器打開.css文件。模板文件在其<link rel="stylesheet" ...>標簽中鏈接了CSS(Thymeleaf在執行模板時會把該標簽中的href替換為th:href)。因此對CSS文件的修改會顯示在頁面中。

第3步:修改顏色。和采用JSP一樣,我們仍然需要嘗試多種不同的顏色組合,使用F5刷新頁面。

完成!

重大區別(That was a big difference)

步驟數量的差別并不重要(在Thymeleaf的例子中也可以使用firebug)。真正重要的區別在于其復雜性,JSP方式中每一步驟需要花費的精力和時間。采用JSP,就必須部署并啟動整個應用程序,這使得JSP不如Thymeleaf方便。

下列情形將進一步體現上述區別的意義:

  • 開發服務器并不在本地,而是遠程服務器。
  • 不僅修改CSS,而且添加或刪除了一些HTML代碼。
  • 還未實現頁面所需的后臺邏輯

最后一點是最重要的一點:如果應用程序仍在開發中,頁面展示所需的Java邏輯還未完成的情況下,我們如何給客戶展示新的顏色?(或者想讓顧客選擇顏色)...

使用JSP作為靜態原型不行嗎?(And what about trying to use the JSP as a static prototype?

你可能會問,我們為什么要那么費事兒的修改JSP,像Thymeleaf一樣直接打開JSP不行嗎?

答案是:NO。

我們可以試一下:我們要把.jsp文件的后綴名改為.html,打開后結果如下圖:


頁面哪去了?其實頁面還是那個頁面。只是為了讓頁面以JSP的方式執行,我們要添加許多JSP標簽和特性。但是改為HTML后,瀏覽器就無法正確的顯示了。

再一次回顧一下雙擊Thymeleaf模板打開后的樣子:


完全不是一個級別的了。。。

Got HTML5?

在一開始的時候,我們就說了我們的頁面是HTML5的。那么為什么不使用一些HTML5表單相關的新特性呢?

例如,<input type="email" ...>標簽可以讓瀏覽器檢查輸入是否是合法的郵件格式。input標簽還添加了一個新屬性placeholder,它的值會默然顯示在輸入框中,焦點移到該輸入框時自動消失。

不錯吧?不幸的是,并非所有瀏覽器都支持(到2011年,Opera 11 和Firefox 4支持),但是我們可以安全的使用這些新特性,因為所有的瀏覽器在遇到不認識的input type(如email)時會默認把它看做text類型的input,并忽略placeholder屬性。

Doing HTML5 with JSP

Spring 3.1之前

Spring MVC的JSP標簽庫在Spring3.1之前不能完全支持HTML5,因而在此之前不能寫email type的input標簽:

<input type="email" id="email" name="email" placeholder="your@email" value="" />

這是不對的。在Spring MVC中不能這樣寫JSP input ,因為我們不能正確地把輸入綁定到form-backing bean的email屬性。為了實現這種功能,需要使用<s:eval/>標簽,該標簽將完成所有的轉換,使純HTML標簽像<sf:email/>標簽一樣運行:

<input type="email" id="email" name="email" placeholder="your@email"
       value="<s:eval expression='subscription.email' />" />


Spring3.1及之后

Spring3.1仍然沒有<sf:email ...>標簽,但是<sf:input ...>標簽允許type屬性的值為email:

<sf:input path="email" type="email" />

上述代碼正確地完成了表單綁定

Doing HTML5 with Thymeleaf

Thymeleaf完全支持HTML5(即使是Spring3.0),因而我們只需修改input標簽的type屬性并添加placeholder屬性,即可使用,它將會正確地綁定屬性、集成到Spring MVC的屬性編輯器,更為重要的是,顯示為原型時也能正常顯示——這是sf:input標簽不支持的——

<input type="email" th:field="*{email}" placeholder="your@email" />

完成!




英文原文鏈接:Spring MVC view layer: Thymeleaf vs. JSP


來自: http://blog.csdn.net//kingzone_2008/article/details/19034615

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!