spring+thymeleaf實現表單驗證數據雙向綁定

前言javascript

  這個教程介紹了Thymeleaf與Spring框架的集成,特別是SpringMvc框架。
  注意Thymeleaf支持同Spring框架的3.和4.版本的集成,可是這兩個版本的支持是封裝在thymeleaf-spring3和thymeleaf-spring4這兩個獨立的庫中,項目中須要根據實際狀況分別引用。
  樣例代碼針對的是spring4.,但通常狀況下,spring3.也能夠無縫使用,所須要的僅僅是改變一下引用庫。css

1 Thymeleaf同Spring的整合
  Thymeleaf與Spring進行整合後,能夠在SpringMVC應用中徹底替代JSP文件。
集成後你將:
  *就像控制JSP同樣,使用SpringMvc的@Controller註解來映射Thymeleaf的模板文件。
  *在模板中使用SpringEL表達式來替換OGNL
  *在模板中建立的表單,徹底支持Beans和結果的綁定,包括使用PropertyEditor,轉換,和驗證等。
  *能夠經過Spring來管理國際化文件顯示國際化信息。
  *注意,在使用本教程以前,您應該充分了解Thymeleaf的標準方言。html

2 Spring標準方言
  爲了更加方便,更快捷的集成,Thymeleaf提供了一套可以與Spring正確工做的特有方言。
  這套方言基於Thymeleaf標準方言實現,它在類 org.thymeleaf.spring.dialect.SpringStandardDialect 中,事實上,他繼承於 org.thymeleaf.standard.StandardDialect 中。java


除了已經出如今標準方言中的全部功能,Spring中還有如下特色:
  *不適用OGNL,而是SpringEL作完變量表達式,所以,全部的${...}和*{...}表達式將用Spring的表達式引擎進行處理。
  *訪問應用context中的beans可使用SpringEL語法:${@myBean.doSomething()}
  *基於表格處理的新屬性:th:field,th:errors和th:errorclass,除此還有一個th:object的新實現,容許它使用表單命令選擇器(??)。
  *一個新的表達式:#themes.code(...),至關於jsp自定義標籤中的spring:theme。
  *在spring4.0集成中的一個新的表達式:#mvc.uri(...),至關於jsp自定義標籤中的spring:mvcUrl(...)
注意,上述這些方言特性是不能再普通的TemplateEngine對象中使用的,應該配置一個org.thymeleaf.spring4.SpringTemplateEngine來執行。web


  其餘thymeleaf基礎使用方法部分不在敘述。spring


建立表單
處理命令對象
  SpringMVC的表單支持bean就是命令對象,這個對象經過對象領域模型的方式提供get和set方法,在瀏覽器創建獲取用戶輸入值的輸入框架。數組

  Thymeleaf須要你顯示的在form標籤內經過th:object屬性指定命令對象:瀏覽器

1 <form action="#" th:action="@{/seedstartermng}" th:object="${seedStarter}" method="post">
2 ...
3 </form>

  這個th:object與其餘的的地方用途是一直的,可是事實上在這種特定狀況下,爲了與SpringMVC框架的正確整合增長了一些特定的限制:
  1.在form標籤中的th:object的值必須是變量表達式(...),只能指定屬性模型屬性的名字,而不能使用屬性導航,這意味着,表達式...),只能指定屬性模型屬性的名字,而不能使用屬性導航,
這意味着,表達式 {seedStarter}是正確的,而${seedStarter.data}則不是。
  2.一個form標籤內只能指定一個th:object屬性,這與html中form標籤不能嵌套的特性相一致。安全

input
  下面是如何將一個input插入到表單中mvc

<input type="text" th:field="*{datePlanted}" />

  正象上邊的代碼所示,新增了一個 th:field 的屬性,這是SpringMVC集成的一個重要特徵,它幫你完成了表單bean和輸入框之間的繁重的綁定工做。能夠看出他在from中的路徑屬性和SpringMVC的jsp標籤庫同樣。
   th:field 屬性的不一樣行爲取決於它所附加的不一樣標籤,包括 <input> , <select> 或 <textarea> (還包括標籤的不一樣type屬性類型),在這種狀況下,時間上上面哪行代碼會是這樣的:

<input type="text" id="datePlanted" name="datePlanted" th:value="*{datePlanted}" />

  事實上,可能比上邊的代碼還要多一些東西,由於 th:field 還可能會註冊一個Spring的轉換服務,包括以前咱們看到的 DateFormatter (甚至這個表達式中沒使用雙大括號),所以,這個日期也將被正確的格式化。
   th:field 的值必須使用選擇表達式,這樣將在這個環境中使用表單bean,而不是上下文變量或SpringMVC的模型屬性。
  相反對於 th:object 這類,它的表達式可使用屬性導航(事實上在JSP的 <form:input 標籤中,可使用任何的路徑屬性表達式)
注意th:field屬性也能夠在HTML5的的新增類型中使用,如 <input type="datetime"> , <input type="color"> 等,有效的增長了對SpringMVC對HTML5支持的完整性。

複選框
 th:field 也能夠用在 checkbox 中,好比以下代碼:

1 <div>
2    <label th:for="${#ids.next('covered')}" th:text="#{seedstarter.covered}">已種植</label>
3    <input type="checkbox" th:field="*{covered}" />
4 </div>

  注意這裏有一些除了複選框以外的好東西,好比外部label和它使用的 #ids.next("covered") 方法,用於當該id的複選框執行的時候獲取它的id值。
那麼爲何咱們須要這個字段的id屬性動態生成呢?由於複選框多是多值的,所以它會給id值添加一個序列號後綴(內部使用 #ids.seq(...) 函數)來保證同一屬性的複選框有不一樣的id值。

咱們能夠看看多值的複選框:

1 <ul>
2   <li th:each="feat : ${allFeatures}">
3     <input type="checkbox" th:field="*{features}" th:value="${feat}" />
4     <label th:for="${#ids.prev('features')}" 
5         th:text="#{${'seedstarter.feature.' + feat}}">Heating</label>
6   </li>
7 </ul>

  注意此次咱們增長了一個 th:value 屬性,由於此次的特徵屬性不是一個布爾值,而是一個數組。

通常狀況下,它的輸出爲:

 1 <ul>
 2   <li>
 3     <input id="features1" name="features" type="checkbox" 
 4          value="SEEDSTARTER_SPECIFIC_SUBSTRATE" />
 5     <input name="_features" type="hidden" value="on" />
 6     <label for="features1">Seed starter-specific substrate</label>
 7   </li>
 8   <li>
 9     <input id="features2" name="features" type="checkbox" 
10         value="FERTILIZER" />
11     <input name="_features" type="hidden" value="on" />
12     <label for="features2">Fertilizer used</label>
13   </li>
14   <li>
15     <input id="features3" name="features" type="checkbox" 
16         value="PH_CORRECTOR" />
17     <input name="_features" type="hidden" value="on" />
18     <label for="features3">PH Corrector used</label>
19   </li>
20 </ul>

  咱們能夠看到一個序列後綴增長在每個id的屬性中, #ids.prev(....) 函數容許咱們把檢索最後一個序列值,生成的一個特定的id。
用不着擔憂那些隱藏域的名稱爲"_features":這是爲了不瀏覽器將未選中的複選框的值在表單提交是沒有自動發送而故意添加的。
還應注意到,若是咱們的表單bean中的feature屬性已經包含了一些特定的值,那麼th:field還將會自動在相應的標籤中增長checked="checked"屬性。


單選框
  單選框的用法和一個非布爾值的多選框使用方式相似,只是他不是多選:

1 <ul>
2   <li th:each="ty : ${allTypes}">
3     <input type="radio" th:field="*{type}" th:value="${ty}" />
4     <label th:for="${#ids.prev('type')}" th:text="#{${'seedstarter.type.' + ty}}">Wireframe</label>
5   </li>
6 </ul>

 

下拉列表
  下拉列表包含兩個部分:<select>標籤和它包含的<option>標籤。在建立這種表單域的時候,只有<select>標籤須要導入th:field屬性,但 th:value 屬性卻在 <option> 標籤中很是重要,由於他們提供了目前選選擇框的選項(使用和非布爾複選框和單選框相似的手段)

使用類型做爲下拉列表:

1 <select th:field="*{type}">
2     <option th:each="type : ${allTypes}" 
3         th:value="${type}" 
4         th:text="#{${'seedstarter.type.' + type}}">Wireframe</option>
5 </select>

  這段代碼理解起來很容易,只是注意屬性優先級讓咱們能夠在option標籤內使用th:each屬性。


動態域
  因爲SpringMVC的高級表單綁定功能,使得咱們可使用複雜的SpringEL表達式來綁定動態表單域到表單bean中。這將容許咱們在 SeedStarter bean 中建立一個新的Row對象,並將這個row的域添加到用戶請求的form中。

  爲了作到這一點,咱們須要在控制器中提供一些新的映射方法,它將根據咱們的特定請求的參數來決定添加或刪除一行咱們定義的.

 1 @RequestMapping(value="/seedstartermng", params={"addRow"})
 2 public String addRow(final SeedStarter seedStarter, final BindingResult bindingResult) {
 3     seedStarter.getRows().add(new Row());
 4     return "seedstartermng";
 5 }
 6 
 7 @RequestMapping(value="/seedstartermng", params={"removeRow"})
 8 public String removeRow(
 9     final SeedStarter seedStarter, final BindingResult bindingResult, 
10     final HttpServletRequest req) {
11     final Integer rowId = Integer.valueOf(req.getParameter("removeRow"));
12     seedStarter.getRows().remove(rowId.intValue());
13     return "seedstartermng";
14 }

如今給form添加一個動態table

 1 <table>
 2   <thead>
 3     <tr>
 4       <th th:text="#{seedstarter.rows.head.rownum}">Row</th>
 5       <th th:text="#{seedstarter.rows.head.variety}">Variety</th>
 6       <th th:text="#{seedstarter.rows.head.seedsPerCell}">Seeds per cell</th>
 7       <th>
 8         <button type="submit" name="addRow" th:text="#{seedstarter.row.add}">Add row</button>
 9 </th>
10     </tr>
11   </thead>
12 <tbody>
13   <tr th:each="row,rowStat : *{rows}">
14     <td th:text="${rowStat.count}">1</td>
15     <td>
16       <select th:field="*{rows[__${rowStat.index}__].variety}">
17       <option th:each="var : ${allVarieties}" 
18             th:value="${var.id}" 
19             th:text="${var.name}">Thymus Thymi</option>
20       </select>
21     </td>
22     <td>
23       <input type="text" th:field="*{rows[__${rowStat.index}__].seedsPerCell}" />
24     </td>
25     <td>
26       <button type="submit" name="removeRow" 
27              th:value="${rowStat.index}" th:text="#{seedstarter.row.remove}">Remove row</button>
28     </td>
29    </tr>
30   </tbody>
31 </table>

  這裏出現了不少東西,但都不難理解,除了這一句:

1 <select th:field="*{rows[__${rowStat.index}__].variety}">
2 ...
3 </select>

  若是你記得Thymeleaf教程,那麼應該明白 __${...}__ 是一種預處理表達式的語法。這是一個在處理整個表達式以前的內部表達式,但爲何用這種方式指定行的索引呢,下面這種方式不行麼:

1 <select th:field="*{rows[rowStat.index].variety}">
2     ...
3 </select>

  嗯事實上,是不行的,他的問題是SpringEL表達式不執行數值中括號裏邊的表達式變量,索引執行上邊的語句時,會獲得一個錯誤的結果,就是字面形式的 row[rowStat.index]  (而不是 row[0],row[1] )而不是行集合中的正確位置,這就是爲何在這裏須要預處理。
  讓咱們看看產生的html後按"添加行"按鈕幾回:

 1 <tbody>
 2   <tr>
 3     <td>1</td>
 4     <td>
 5       <select id="rows0.variety" name="rows[0].variety">
 6         <option selected="selected" value="1">Thymus vulgaris</option>
 7         <option value="2">Thymus x citriodorus</option>
 8         <option value="3">Thymus herba-barona</option>
 9         <option value="4">Thymus pseudolaginosus</option>
10         <option value="5">Thymus serpyllum</option>
11       </select>
12     </td>
13     <td>
14       <input id="rows0.seedsPerCell" name="rows[0].seedsPerCell" type="text" value="" />
15     </td>
16     <td>
17       <button name="removeRow" type="submit" value="0">Remove row</button>
18     </td>
19   </tr>
20   <tr>
21     <td>2</td>
22     <td>
23       <select id="rows1.variety" name="rows[1].variety">
24         <option selected="selected" value="1">Thymus vulgaris</option>
25         <option value="2">Thymus x citriodorus</option>
26         <option value="3">Thymus herba-barona</option>
27         <option value="4">Thymus pseudolaginosus</option>
28         <option value="5">Thymus serpyllum</option>
29       </select>
30     </td>
31     <td>
32        <input id="rows1.seedsPerCell" name="rows[1].seedsPerCell" type="text" value="" />
33     </td>
34     <td>
35       <button name="removeRow" type="submit" value="1">Remove row</button>
36     </td>
37   </tr>
38 </tbody>

 

驗證和錯誤信息
  讓咱們看看當有錯誤的時候如何給一個表單域一個CSS類:

1 <input type="text" th:field="*{datePlanted}" 
2            th:class="${#fields.hasErrors('datePlanted')}? fieldError" />

  能夠看到, #fields.hasErrors(...) 函數接受一個表達式參數(datePlanted),返回一個布爾值告訴field該字段是否有驗證錯誤。
咱們能夠根據他們各自的field獲取全部的錯誤:

1 <ul>
2       <li th:each="err : ${#fields.errors('datePlanted')}" th:text="${err}" />
3 </ul>

  經過迭代,咱們可使用 th:errors ,一個專門用於建立一個經過制定選擇器篩選的錯誤列表的屬性,經過    分隔。

1 <input type="text" th:field="*{datePlanted}" />
2 <p th:if="${#fields.hasErrors('datePlanted')}" th:errors="*{datePlanted}">Incorrect date</p>

 

簡單錯誤基礎css樣式,th:errorclass
  在上邊的例子中,若是字段有錯誤,將爲表單的input域設置一個css類,由於這種方式很常見,Thymeleaf提供了一個特定的屬性爲  th:errorclass 
  應用於form域的標籤(input,select,textarea等),它將從現有的name屬性或th:field屬性字段的名詞相同的屬性,若是發生錯誤,則將制定的css類追加到標籤中。

<input type="text" th:field="*{datePlanted}" class="small" th:errorclass="fieldError" />

  若是datePlanted發生錯誤,則: 

<input type="text" id="datePlanted" name="datePlanted" value="2013-01-01" class="small fieldError" />

 

所有錯誤
  若是咱們想要在form中顯示全部的錯誤呢?咱們只須要經過'*'或'all'(等價)來查詢 #field.hasErrors(...) 方法和 #field.errors(...) 方法:

1 <ul th:if="${#fields.hasErrors('*')}">
2     <li th:each="err : ${#fields.errors('*')}" th:text="${err}">Input is incorrect</li>
3 </ul>

  在上邊的例子中,咱們獲得全部的錯誤並迭代他們:

1 <ul>
2     <li th:each="err : ${#fields.errors('*')}" th:text="${err}" />
3 </ul>

創建一個以<Enter>分隔的列表:

1 <p th:if="${#fields.hasErrors('all')}" th:errors="*{all}">Incorrect date</p>

  最後,注意 #field.hasErrors("") 等效的屬性 #fields.hasAnyErrors() 和 #fields.errors() 的等效的 #fields.allErrors() ,可使用喜歡的任何語法。

1 <div th:if="${#fields.hasAnyErrors()}">
2     <p th:each="err : ${#fields.allErrors()}" th:text="${err}">...</p>
3 </div>

 

全局錯誤
  Spring表單還有一種錯誤,全局錯誤,都是些不與窗體的任何特定字段關聯的錯誤。
  Thymeleaf提供了一個global的常量來訪問這些錯誤。

1 <ul th:if="${#fields.hasErrors('global')}">
2     <li th:each="err : ${#fields.errors('global')}" th:text="${err}">Input is incorrect</li>
3 </ul>

Incorrect date以及等效的 #field.hasGlobalErrors() 和 #field.globalErrors() 方法。

1 <div th:if="${#fields.hasGlobalErrors()}">
2     <p th:each="err : ${#fields.globalErrors()}" th:text="${err}">...</p>
3 </div>

 

在表單外部顯示錯誤
表單驗證錯誤也能夠在表單外部顯示,方法是經過變量(即${...})的內部選擇變量(*{...})增長表單bean的名字做爲前綴的方式。

 1 <form>
 2     <div th:errors="${myForm}">...</div>
 3     <div th:errors="${myForm.date}">...</div>
 4     <div th:errors="${myForm.*}">...</div>
 5     <div th:if="${#fields.hasErrors('${myForm}')}">...</div>
 6     <div th:if="${#fields.hasErrors('${myForm.date}')}">...</div>
 7     <div th:if="${#fields.hasErrors('${myForm.*}')}">...</div>
 8     <form th:object="${myForm}">
 9     ...
10 </form>

 

 

富錯誤對象
  Thymeleaf提供了以bean的形式(代替單純的String)提供錯誤信息的能力,包括fieldName(String),message(String),和global(String)屬性的錯誤。這些錯誤能夠經過工具方法#fields.datailedErrors()來實現:

1 <ul>
2   <li th:each="e : ${#fields.detailedErrors()}" th:class="${e.global}? globalerr : fielderr">
3     <span th:text="${e.global}? '*' : ${e.fieldName}">The field name</span> |
4     <span th:text="${e.message}">The error message</span>
5   </li>
6 </ul>

 

轉換服務
 配置
  就像前文所說,Thymeleaf能夠在上下文中註冊一個轉換服務,再次看一下他的配置信息

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans ...>
 3     ... 
 4     <mvc:annotation-driven conversion-service="conversionService" />
 5 ...
 6 <!-- **************************************************************** -->
 7 <!-- CONVERSION SERVICE -->
 8 <!-- Standard Spring formatting-enabled implementation -->
 9 <!-- **************************************************************** -->
10   <bean id="conversionService"
11 class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
12   <property name="formatters">
13   <set>
14      <bean class="thymeleafexamples.stsm.web.conversion.VarietyFormatter" />
15      <bean class="thymeleafexamples.stsm.web.conversion.DateFormatter" />
16      </set>
17     </property>
18   </bean>
19 ...
20 </beans>

 


${{...}}語法
  轉換服務能夠經過 ${{...}} 語法很輕鬆的實現對象到字符串的轉換或格式化:
變量語法 ${{...}} 
選擇變量語法 *{{...}} 
  例如,將一個Integer型轉換爲字符串類型,並經過逗號來分隔:

1 <p th:text="${val}">...</p>
2 <p th:text="${{val}}">...</p>

返回結果爲:

1 <p>1234567890</p>
2 <p>1,234,567,890</p>

 

 

表單中使用
  咱們以前看到的每個th:field屬性都將始終使用轉換服務:

<input type="text" th:field="*{datePlanted}" />

等效於:

<input type="text" th:field="*{{datePlanted}}" />

注意這是惟一一種在表達式中使用單大括號的轉換服務。

 

#conversions工具對象
conversions工具對象表達式容許手動執行轉換服務:

<p th:text="${'Val: ' + #conversions.convert(val,'String')}">...</p>

工具對象表達式的語法爲:
 conversions.convert(Object,Class) :將對象轉換爲指定的類
 conversions.convert(Object,String) :和上邊相同,可是指定的目標爲String類(java.lang包名能夠省略)

 

渲染片斷模板
  Thymeleaf提供了將一個模板只渲染一部分,並做爲一個片斷返回的能力。

這是一個很是有用的組件化工具,好比,它能夠用於執行AJAX的Controller的調用,用於在已經加載的瀏覽器中返回一個片斷標籤(如用於更新選擇,啓用禁用按鈕等)。

片斷渲染可使用Thymeleaf的片斷規範:一個實現了 org.thymeleaf.fragment.IFragmentSpec 接口的對象。

最經常使用的一個實現是 org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec 類,它容許一個片斷規範包括以前說過的th:insert,th:replace使用DOM選擇器。

  在視圖bean中指定片斷
視圖bean是在應用程序上下文中聲明的 org.thymeleaf.spring4.view.ThymeleafView 的bean,它容許這樣定義一個片斷:

1 <bean name="content-part" class="org.thymeleaf.spring4.view.ThymeleafView">
2     <property name="templateName" value="index" />
3     <property name="fragmentSpec">
4 <bean 
5  class="org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec"
6 c:selectorExpression="content" />
7 </property>
8 </bean>

 

經過上邊的bean的定義,若是controller返回一個content-part(bean的名字),

1 @RequestMapping("/showContentPart")
2 public String showContentPart() {
3     ...
4     return "content-part";
5 }

Thymeleaf將只返回index模板的content片斷。一旦前綴後綴都設置並匹配,那麼它可能爲/WEB-INF/templates/index.html,

 1 <!DOCTYPE html>
 2 <html>
 3   ...
 4   <body>
 5     ...
 6     <div th:fragment="content">
 7        只有這裏渲染!!
 8     </div>
 9   ...
10   </body>
11 </html>

  另外應該注意到,由於Thymeleaf可使用DOM選擇器,全部咱們能夠不用任何 th:fragment 屬性,而只用id屬性來選擇一個片斷,如:

1 <bean name="content-part" class="org.thymeleaf.spring4.view.ThymeleafView">
2   <property name="fragmentSpec">
3 <bean class="org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec"
4 c:selectorExpression="#content" />
5   </property>
6   <property name="templateName" value="index" />
7 </bean>

一樣完美的適用:

 1 <!DOCTYPE html>
 2 <html>
 3   ...
 4  <body>
 5   ...
 6     <div id="content">
 7       只有這裏渲染!!
 8     </div>
 9   ...
10   </body>
11 </html>

 

經過控制權的返回值指定片斷
  不聲明一個視圖bean,能夠從控制器本身就可使用與片斷相同的語法,相似於th:insert,th:rplace屬性等,如:

1 @RequestMapping("/showContentPart")
2 public String showContentPart() {
3     ...
4     return "index :: content";
5 }    

  固然,一樣可使用基於DOM選擇器的功能,全部咱們也能夠是選擇使用基於標準的HTML屬性,如id="content"

1 @RequestMapping("/showContentPart")
2 public String showContentPart() {
3     ...
4     return "index :: #content";
5 }

也可使用參數:

1 @RequestMapping("/showContentPart")
2 public String showContentPart() {
3     ...
4     return "index :: #content ('myvalue')";
5 }

 

 

與RequestDataValueProcessor集成
  如今Thymeleaf無縫的與Spring的RequestDataValueProcessor接口集成,這個接口容許攔截連接URLS,表達URLS和表達域的值,以及爲了啓用安全,如抵禦CSRF而自動透明的添加一些隱藏域。

在應用的上下文中能夠簡單的配置RequestDataValueProcessor:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4 xsi:schemaLocation="http://www.springframework.org/schema/beans
 5 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
 6 
 7 ...
 8 
 9 <bean name="requestDataValueProcessor"
10 class="net.example.requestdata.processor.MyRequestDataValueProcessor" />
11 
12 </beans>

Thymeleaf將經過這種方式使用它:

  在渲染URL以前,th:href和th:src將會調用 RequestDataValueProcessor.processUrl(...) 
  在渲染表單的action屬性以前,th:action會調用 RequestDataValueProcessor.processAction(...) ,另外他會檢查標籤,由於通常來講這是使用action的惟一一個地方,而且在的關閉標籤以前執行 RequstDataValueProcessor.getExtraHiddenFields(...) 用來新增返回的hidden域。

  在渲染value屬性以前,th:value會調用 RequestDataProcessor.processFormFieldValue(...) ,除非在這個標籤中存在了th:field(這時候th:field屬性起做用)
  當存在th:field的時候,在渲染value屬性以前會調用 RequestDataValueProcessor.processFormFieldValue(...) 處理這個屬性值(<textarea>處理內容值)
  此功能只有Spring3.x之後使用

 

綁定地址到Controller
  在Spring4.1以後的版本中,Spring容許經過註解直接從從視圖連接到控制器,而不須要知道這些控制器映射的URI.

  在Thymeleaf中能夠經過 #mvc.url(...) 表達式方法調用Controller中符合駝峯命名規則的方法(get,set),調用的方式爲方法的名字,即至關於jsp的spring:mvcUrl(...)自定義方法。

好比

1 public class ExampleController {
2   @RequestMapping("/data")
3   public String getData(Model model) { ... return "template" }
4       @RequestMapping("/data")
5       public String getDataParam(@RequestParam String type) {
6            ...
7           return "template" }
8 }

 

下邊是一個連接到它的方法:

1 <a th:href="${(#mvc.url('EC#getData')).build()}">獲取Data參數</a>
2 <a th:href="${(#mvc.url('EC#getDataParam').arg(0,'internal')).build()}">獲取Data參數</a>


Spring WebFlow的集成
  基礎配置
  Thymeleaf-spring4集成包包括與Spring WebFlow 2.3.x的集成

  WebFlow包括當特定的事件(過渡)被觸發時渲染頁面片斷的一些Ajax的功能,將來讓Thymeleaf參加這些Ajax請求,咱們將使用一個不經過的視圖解析器的實現,它這樣配置:

1 <bean id="thymeleafViewResolver" class="org.thymeleaf.spring4.view.AjaxThymeleafViewResolver">
2   <property name="viewClass" value="org.thymeleaf.spring4.view.FlowAjaxThymeleafView" />
3   <property name="templateEngine" ref="templateEngine" />
4 </bean>

  而後在ViewResolver中配置WebFlow的 ViewFactoryCreator .

1 <bean id="mvcViewFactoryCreator" 
2 class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
3   <property name="viewResolvers" ref="thymeleafViewResolver"/>
4 </bean>

  在這裏能夠指定模板的視圖狀態

1 <view-state id="detail" view="bookingDetail">
2     ...
3 </view-state>

  在上邊的實例中,bookingDetail是Thymeleaf模板一般使用的一個方式,是模板引擎內任何模板解析器均可以懂的

 

 


Ajax片斷
  WebFlow的片斷規範容許片斷經過標籤呈現,就像這樣:

1 <view-state id="detail" view="bookingDetail">
2   <transition on="updateData">
3     <render fragments="hoteldata"/>
4   </transition>
5 </view-state>

  這些片斷(即hoteldata)能夠是逗號分隔的列表標記在th:fragment標籤中。

1 <div id="data" th:fragment="hoteldata">

  這裏內容替換</div>

  永遠記住,指定的片斷必須有一個id屬性,這樣瀏覽器運行的SpringJavaScript庫才能對標籤進行替換。

  

  標籤,也能夠經過DOM選擇器設定

1 <view-state id="detail" view="bookingDetail">
2   <transition on="updateData">
3     <render fragments="[//div[@id='data']]"/>
4   </transition>
5 </view-state>

  這將意味着th:fragment不在須要:

1 <div id="data">
2     This is a content to be changed
3 </div>

  而出發updateData後轉換的代碼:

 1 <script type="text/javascript" th:src="@{/resources/dojo/dojo.js}"></script>
 2 <script type="text/javascript" th:src="@{/resources/spring/Spring.js}"></script>
 3 <script type="text/javascript" th:src="@{/resources/spring/Spring-Dojo.js}"></script>
 4 
 5 ...
 6 
 7   <form id="triggerform" method="post" action="">
 8     <input type="submit" id="doUpdate" name="_eventId_updateData" value="Update now!" />
 9   </form>
10 
11 <script type="text/javascript">
12      Spring.addDecoration(
13          new Spring.AjaxEventDecoration({
14               formId:'triggerform',
15               elementId:'doUpdate',
16               event:'onclick'
17         }));
18 </script>

 

 

轉載: 

相關文章
相關標籤/搜索