Thymeleaf从入门到专家-第三篇Thymeleaf使用

1、th:object使用方法

用于表单数据对象绑定,将表单绑定到后台controller的一个JavaBean参数,常与th:field一起使用进行表单数据绑定。

官方示例:

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

示例:

<h1>th:object 使用</h1>
<form th:action="@{/user/save}" th:object="${user}" method="post">
    <input type="text" th:field="*{name}" value="vesus"/>
    <input type="submit" value="submit"/>
</form>

@RequestMapping("/save")
public String saveUser(@ModelAttribute(value = "user") User user){
    System.out.println(user);
    return "success";
}
  • Values for th:object attributes in form tags must be variable expressions (${…}) specifying only the name of a model attribute, without property navigation. This means that an expression like ${seedStarter} is valid, but ${seedStarter.data} would not be.

  • Once inside the tag, no other th:object attribute can be specified. This is consistent with the fact that HTML forms cannot be nested.

  • 表单标记中的th:object属性的值必须是变量表达式($ {…})仅指定模型属性的名称,不带属性导航。这意味着像$ {seedStarter}这样的表达式是有效的,但$ {seedStarter.data}不会。

  • 进入标记后,不能指定其他th:object属性。这与HTML表单无法嵌套这一事实是一致的。

注意点:

  • 实体类必须要有默认的构造函数

2、input输入

官方示例:

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

As you can see, we are introducing a new attribute here: th:field. This is a very important feature for Spring MVC integration because it does all the heavy work of binding your input with a property in the form-backing bean. You can see it as an equivalent of the path attribute in a tag from Spring MVC’s JSP tag library.

The th:field attribute behaves differently depending on whether it is attached to an , or tag (and also depending on the specific type of tag). In this case (input[type=text]), the above line of code is similar to:

如您所见,我们在这里引入了一个新属性:th:field。这是Spring MVC集成的一个非常重要的特性,因为它完成了将输入与表单支持bean中的属性绑定的所有繁重工作。您可以将其视为Spring MVC的JSP标记库中的标记中的path属性的等价物。

th:field属性的行为有所不同,具体取决于它是否附加到or 标签并且还取决于具体的类型,在这种情况下(input[type=text]),上面的代码类似于

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

Values for th:field attributes must be selection expressions (*{…}), which makes sense given the fact that they will be evaluated on the form-backing bean and not on the context variables (or model attributes in Spring MVC jargon).

Contrary to the ones in th:object, these expressions can include property navigation (in fact any expression allowed for the path attribute of a form:input JSP tag will be allowed here).

Note that th:field also understands the new types of element introduced by HTML5 like <input type=“datetime” … />, <input type=“color” … />, etc., effectively adding complete HTML5 support to Spring MVC.

th:field属性的值必须是选择表达式(* {…}),这是有意义的,因为它们将在表单支持bean上进行评估,而不是在上下文变量(或Spring MVC术语中的模型属性)上进行评估)。

与th:object中的对象相反,这些表达式可以包含属性导航(实际上,此处允许使用 JSP标记的path属性允许的任何表达式)。

th:field也支持html5的新input类型,像<input type=“datetime”…/>,<input type=“color”…/>等,有效地为Spring MVC添加完整的HTML5支持。

3、Checkbox fields

官方示例

<div>
  <label th:for="${#ids.next('covered')}" th:text="#{seedstarter.covered}">Covered</label>
  <input type="checkbox" th:field="*{covered}" />
</div>

Because checkboxes are potentially multi-valued, and thus their id values will always be suffixed a sequence number (by internally using the #ids.seq(…)function) in order to ensure that each of the checkbox inputs for the same property has a different id value.

因为复选框可能是多值的,因此它们的id值将始终以序列号为后缀(通过内部使用#ids.seq(…)函数),以确保相同属性的每个复选框输入具有不同的id值。

示例

<form th:action="@{/user/save}" th:object="${user}" method="post">
<div th:each="inerest:${interestlist}">
    <label th:for="${#ids.next('id')}" th:text="${inerest.name}">Covered</label>
    <input type="checkbox" th:field="*{id}" th:value="${inerest.id}" />
</div>
    <input type="submit" value="submit"/>
</form>

//添加兴趣爱好
List interestlist = new ArrayList();
Interests interests1 = new Interests(1,"movie");
Interests interests2 = new Interests(2,"music");
interestlist.add(interests1);
interestlist.add(interests2);
model.addAttribute("interestlist",interestlist);

thymeleaf生成的源代码

<ul>
    <li>
        <input type="checkbox" value="1" id="id1" name="id" /><input type="hidden" name="_id" value="on" />
        <label for="id1">movie</label>
    </li>
    <li>
        <input type="checkbox" value="2" id="id2" name="id" /><input type="hidden" name="_id" value="on" />
        <label for="id2">music</label>
    </li>
</ul>

4、单选按钮字段(Radio Button fields)

Radio button fields are specified in a similar way to non-boolean (multi-valued) checkboxes —except that they are not multivalued, of course:

单选按钮字段的指定方式与非布尔(多值)复选框类似 - 当然它们不是多值的

官方示例

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

5、下拉列表/列表选择器(Dropdown/List selectors)

Select fields have two parts: the tag and its nested tags. When creating this kind of field, only the tag has to include a th:field attribute, but the th:value attributes in the nested tags will be very important because they will provide the means of knowing which is the currently selected option (in a similar way to non-boolean checkboxes and radio buttons).

下拉列表包含两部分,和标签,在创建这种下拉列表时,只有标签包含 th:field属性,但中的th:value属性将非常重要,因为它们将提供了解当前所选选项的方法(与非布尔复选框和单选按钮类似)

官方示例

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

6、Dynamic fields

官方示例

<table>
  <thead>
    <tr>
      <th th:text="#{seedstarter.rows.head.rownum}">Row</th>
      <th th:text="#{seedstarter.rows.head.variety}">Variety</th>
      <th th:text="#{seedstarter.rows.head.seedsPerCell}">Seeds per cell</th>
      <th>
        <button type="submit" name="addRow" th:text="#{seedstarter.row.add}">Add row</button>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr th:each="row,rowStat : *{rows}">
      <td th:text="${rowStat.count}">1</td>
      <td>
        <select th:field="*{rows[__${rowStat.index}__].variety}">
          <option th:each="var : ${allVarieties}" 
                  th:value="${var.id}" 
                  th:text="${var.name}">Thymus Thymi</option>
        </select>
      </td>
      <td>
        <input type="text" th:field="*{rows[__${rowStat.index}__].seedsPerCell}" />
      </td>
      <td>
        <button type="submit" name="removeRow" 
                th:value="${rowStat.index}" th:text="#{seedstarter.row.remove}">Remove row</button>
      </td>
    </tr>
  </tbody>
</table>

Quite a lot of things to see here, but not much we should not understand by now… except for one strange thing

在这里可以看到很多东西,但现在我们不应该理解太多…除了一件奇怪的事情:

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

If you recall from the “Using Thymeleaf” tutorial, that ${…} syntax is a preprocessing expression, which is an inner expression that is evaluated before actually evaluating the whole expression. But why that way of specifying the row index? Wouldn’t it be enough with:

回忆一下“使用Thymeleaf”教程,那么__ $ {…} __语法是一个预处理表达式,它是一个在实际计算整个表达式之前计算的内部表达式。但为什么这种方式指定行索引?

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

well, actually, no. The problem is that Spring EL does not evaluate variables inside array index brackets, so when executing the above expression we would obtain an error telling us that rows[rowStat.index] (instead of rows[0], rows[1], etc) is not a valid position in the rows collection. That’s why preprocessing is needed here.

实际上,没有。问题是Spring EL没有计算数组索引括号内的变量,所以在执行上面的表达式时,我们会得到一个错误告诉我们行[rowStat.index](而不是rows [0],rows [1]等)不是rows集合中的有效位置。这就是为什么需要预处理的原因。

示例

<h1>Dynamic fields使用</h1>
<table>
    <thead>
    <tr>
        <td>id</td>
        <td>index</td>
        <td>count</td>
        <td>年龄</td>
        <td>姓名</td>
        <td>昵称</td>
    </tr>
    </thead>
    <tbody>
    <tr th:each="user,userStat:${users}">
        <td th:text="${user.id}">1</td>
        <td th:text="${userStat.index}">1</td>
        <td th:text="${userStat.count}">1</td>
        <td th:text="*{users[__${userStat.index}__].name}">1</td>
        <td th:text="${user.age}">1</td>
        <td th:text="${user.nickName}">1</td>
    </tr>
    </tbody>
</table>

List list = new ArrayList();
for (int i = 0; i < 10; i++) {
    User user = new User(i,"vesus"+i,21+i,"加糖咖啡"+i);
    list.add(user);
}
model.addAttribute("users",list);

7、Field errors

let’s see how we could set a specific CSS class to a field if it has an error:

让我们看看如果它有一个错误我们如何设置一个特定的CSS类到字段

官方示例

<h1>Filed Errors使用</h1>
<input type="text" th:field="*{user.name}" th:class="${#fields.hasErrors('user.name')}? fieldError" />

<ul>
    <li th:each="err : ${#fields.errors('user.name')}" th:text="${err}" />
</ul>

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

示例

User实体增加验证框架

@NotEmpty(message = "name is null ")
private String name ; 

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

We could also obtain all the errors for that field and iterate them

我们还可以获取该字段的所有错误并迭代它们

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

Instead of iterating, we could have also used th:errors, a specialized attribute which builds a list with all the errors for the specified selector, separated by
:

我们也可以使用th:errors,一个专门的属性,它构建一个包含指定选择器的所有错误的列表,由

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

Applied to a form field tag (input, select, textarea…), it will read the name of the field to be examined from any existing name or th:field attributes in the same tag, and then append the specified CSS class to the tag if such field has any associated errors:

应用于表单字段标记(input,select,textarea …),它将从同一标记中的任何现有名称或th:字段属性读取要检查的字段的名称,然后将指定的CSS类附加到标记如果此类字段有任何相关错误

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

If datePlanted has errors, this will render as:

如果datePlanted有错误,则会显示为:

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

8、All errors

And what if we want to show all the errors in the form? We just need to query the #fields.hasErrors(…) and #fields.errors(…) methods with the ‘*’ or ‘all’ constants (which are equivalent):

如果我们想要显示表单中的所有错误怎么办?我们只需要使用’*'或’all’常量(等效)查询#fields.hasErrors(…)和#fields.errors(…)方法:

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

As in the examples above, we could obtain all the errors and iterate them…

如上例所示,我们可以获取所有错误并迭代它们…

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

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

Finally note that #fields.hasErrors(’’) is equivalent to #fields.hasAnyErrors() and #fields.errors(’’) is equivalent to #fields.allErrors().

#fields.hasErrors(’’)等同于#fields.hasAnyErrors()和#fields.errors(’’)等同于#fields.allErrors()。

9、Global errors

There is a third type of error in a Spring form: global errors. These are errors that are not associated with any specific fields in the form, but still exist.

Thymeleaf offers the global constant for accessing these errors:

Spring表单中存在第三种类型的错误:全局错误。这些错误与表单中的任何特定字段无关,但仍然存在。

Thymeleaf为访问这些错误提供了全局常量

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

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

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

10、Displaying errors outside forms

Form validation errors can also be displayed outside forms by using variable (${…}) instead of selection (*{…}) expressions and prefixing the name of the form-backing bean:

表单验证错误也可以通过使用变量($ {…})而不是选择(* {…})表达式并在表单支持bean的名称前面显示在表单外部

<div th:errors="${myForm}">...</div>
<div th:errors="${myForm.date}">...</div>
<div th:errors="${myForm.*}">...</div>

<div th:if="${#fields.hasErrors('${myForm}')}">...</div>
<div th:if="${#fields.hasErrors('${myForm.date}')}">...</div>
<div th:if="${#fields.hasErrors('${myForm.*}')}">...</div>

<form th:object="${myForm}">
    ...
</form>

11、Rich error objects

Thymeleaf offers the possibility to obtain form error information in the form of beans (instead of mere strings), with the fieldName (String), message (String) and global (boolean) attributes.

These errors can be obtained by means of the #fields.detailedErrors() utility method:

Thymeleaf提供了使用fieldName(String),message(String)和global(boolean)属性以bean(而不仅仅是字符串)的形式获取表单错误信息的可能性。

这些错误可以通过#fields.detailedErrors()实用程序方法获得

<ul>
    <li th:each="e : ${#fields.detailedErrors()}" th:class="${e.global}? globalerr : fielderr">
        <span th:text="${e.global}? '*' : ${e.fieldName}">The field name</span> |
        <span th:text="${e.message}">The error message</span>
    </li>
</ul>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值