3.Thymeleaf模板

1.注释

1.1标准HTML/XML注释

Thymeleaf不会处理这些注释中的任何内容,并将逐字复制到结果中。

<!-- User info follows -->

1.2Thymeleaf解析器级别的注释块

Thymeleaf将删除<!--/**/-->标记,以及标记之间的所有内容。

//形式一
<!--/* This code will be removed at Thymeleaf parsing time! */-->

//形式二
<!--/*--> 
  <div>
     you can see me only before Thymeleaf processes me!
  </div>
<!--*/-->

1.3Thymeleaf仅原型注释块

Thymeleaf将删除<!--/*//*/-->标记,但不会删除其内容。

//源代码
<span>hello!</span>
<!--/*/
  <div th:text="${...}">
    ...
  </div>
/*/-->
<span>goodbye!</span>
//解析时
<span>hello!</span>
 
  <div th:text="${...}">
    ...
  </div>
 
<span>goodbye!</span>

2.字面量

2.1数字字面量

<p>The year is <span th:text="2013">1492</span>.</p>
<p>In two years, it will be <span th:text="2013 + 2">1494</span>.</p>

2.2布尔字面量

//false写在大括号外面,所以 Thymeleaf 负责处理它
<div th:if="${user.isAdmin()} == false"> ...

//false写在大括号内,这将是 OGNL/SpringEL 引擎的责任
<div th:if="${user.isAdmin() == false}"> ...

2.3文本字面量

文本字面量就是定义在单引号之间的字符串。它们可以包含任何字符,但由于单引号是有意义的,如果需要使用单引号,您应该使用\' 转义其中的任何单引号。

<p>
  Now you are looking at a <span th:text="'working web application'">template file</span>.
</p>

2.4null字面量

<div th:if="${variable.something} == null"> ...

2.5字面量标记

数字、布尔值和 null 字面量实际上是字面量标记的一种特殊情况。

这些标记允许在标准表达式中进行一些简化。它们的工作方式与文本字面量('...') 完全相同,但它们只允许使用字母 (A-Z和 a-z)、数字 (0-9)、括号 ([和 ])、点 (.)、连字符 (-) 和下划线 (_)。所以没有空格,没有逗号等。

标记不需要任何引号。所以我们可以这样做:

<div th:class="content">...</div>

代替:

<div th:class="'content'">...</div>

3.运算符

3.1字符串连接

文本,无论是字面量还是计算变量或消息表达式的结果,都可以使用+运算符轻松附加。

<span th:text="'The name of the user is ' + ${user.name}">

3.2字面量替换

字面量替换允许轻松格式化包含来自变量的值的字符串,而无需在字面量后面附加'...' + '...'

这些替换必须用竖线 ( |) 包围,例如:

<span th:text="|Welcome to our application, ${user.name}!|">

这相当于:

<span th:text="'Welcome to our application, ' + ${user.name} + '!'">

字面量替换可以与其他类型的表达式组合:

<span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">

在字面量替换|...|中只允许使用变量/消息表达式 ( ${...}*{...},#{...} )。没有其它字面量('...')、布尔/数字标记、条件表达式等。

3.3算术运算

请注意,其中一些运算符存在文本别名:( div/mod%)。

//负号(一元运算符)
-
//二元运算符
+,  -,  *,  /, %

3.4比较和相等运算

//比较
>, <, >=, <= (&gt, &lt, &ge, &le)
//相等
==, != (&eq, &neq/&ne)

3.5布尔逻辑运算

//逻辑非(一元运算符)
!, not

//二元运算符
and, or

3.6条件运算

condition为真时,运行then,否则返回空。

// (condition)? (then)
<tr th:class="${row.even}? 'alt'">
  ...
</tr>

condition为真时,运行then,否则运行else。

// (condition)? (then) : (else)
<tr th:class="${row.even}? 'even' : 'odd'">
  ...
</tr>

3.7默认表达式

如果计算结果不为 null,则使用第一个表达式,如果结果为 null,则使用第二个表达式。

(value) ?: (defaultvalue)
//示例
<div th:object="${session.user}">
  ...
  <p>Age: <span th:text="*{age}?: '(no age specified)'">27</span>.</p>
</div>

//等同于
<p>Age: <span th:text="*{age != null}? *{age} : '(no age specified)'">27</span>.</p>

3.8无操作运算

No-Operation 标记由下划线符号 (_) 表示。

这个标记背后的想法是指定表达式的期望结果是什么都不做,即完全就好像可处理属性(例如th:text)根本不存在一样。

<span th:text="${user.name} ?: 'no user authenticated'">...</span>

//更简洁和通用的代码
<span th:text="${user.name} ?: _">no user authenticated</span>

3.9数据转换/格式化

Thymeleaf为变量 ( ${...} ) 和选择 ( *{...} ) 表达式定义了双括号语法,允许我们通过配置的转换服务应用数据转换。

${{...}}
*{{...}}

4.表达式

4.1#{...}消息表达式

//未传参
home.welcome=¡Bienvenido a nuestra tienda de comestibles!
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
//传参
home.welcome=¡Bienvenido a nuestra tienda de comestibles, {0}!
<p th:utext="#{home.welcome(${session.user.name})}">
  Welcome to our grocery store, Sebastian Pepper!
</p>

4.2${...}变量表达式

//普通变量
<p>Today is: <span th:text="${today}">13 february 2011</span>.</p>
//对象变量
Established locale country: <span th:text="${#locale.country}">US</span>.

4.3*{...}选择变量表达式

<div th:object="${session.user}">
  <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
  <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
  <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>

//等同于
<div>
  <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p>
  <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
  <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
</div>

4.4@{...}链接 URL 表达式

//绝对URL
@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}

//输出
http://localhost:8080/gtvg/order/details?orderId=3
//相对页面(相对URL)
@{user/login.html}
//相对上下文(相对URL)
@{/itemdetails?id=3}

@{/order/details(orderId=${o.id})}
//输出
/gtvg/order/details?orderId=3

@{/order/{orderId}/details(orderId=${o.id})}
//输出
/gtvg/order/3/details

//多个参数
@{/order/process(execId=${execId},execType='FAST')}
//相对服务器(相对URL)
@{~/billing/processInvoice}
//相对协议URL(相对URL)
@{//code.jquery.com/jquery-2.0.3.min.js}

4.5~{...}片段表达式

~{...}是可以省略的。

//引入某个模板文件中的某个选择器或片段
~{templatename::selector} 或 ~{templatename::fragmentname}
//引入某个模板文件
~{templatename}
//引入同一个模板文件中的选择器或片段
~{::selector} 或 ~{this::selector}
//引入空片段
~{}
<div th:insert="~{commons :: main}">...</div>
<div th:with="frag=~{footer :: #main/text()}">
  <p th:insert="${frag}">
</div>

5.属性

5.1xmlns:th、th:href

xmlns:th:所有th:*属性的命名空间定义。

th:href:超链接的目标URL。

<html xmlns:th="http://www.thymeleaf.org"></html>
th:href="@{/css/gtvg.css}"

5.2th:text、th:utext

th:text:使用外部化文本替换元素标签之间的内容,外部化文本会被转义。

th:utext:使用外部化文本替换元素标签之间的内容,外部化文本不会被转义。

th:text="外部化文本"
th:utext="外部化文本"

th:text的内联简写对应于[[...]]th:utext的内联简写对应于[(...)]。能在th:text和th:utext中的表达式同等地在对应的内联语法中使用。

<p>Hello, <span th:text="${session.user.name}">Sebastian</span>!</p>
//内联简写
<p>Hello, [[${session.user.name}]]!</p>
msg = 'This is <b>great!</b>'
<p>The message is "[(${msg})]"</p>

//输出
<p>The message is "This is <b>great!</b>"</p>
//示例
home.welcome=Welcome to our <b>fantastic</b> grocery store!

<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
//输出
<p>Welcome to our &lt;b&gt;fantastic&lt;/b&gt; grocery store!</p>

<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
//输出
<p>Welcome to our <b>fantastic</b> grocery store!</p>

5.3th:attr、th:attrappend、th:attrprepend

th:attr:设置任意属性的值。

<form action="subscribe.html" th:attr="action=@{/subscribe}">

<input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>

<img src="../../images/gtvglogo.png" 
    th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />

th:attrappendth:attrprepend:将计算结果附加(后缀)或前置(前缀)到现有属性值。

例如,当CSS类将取决于用户所做的事情而不同时:

<input type="button" value="Do it!" class="btn" th:attrappend="class=${' ' + cssStyle}" />

当用户行为需要传递给cssStyle变量为warning时,可以为:

<input type="button" value="Do it!" class="btn warning" />

5.4th:*、th:alt-title、th:lang-xmllang

th:*th:attr创建属性的方式不是很优雅,可以使用th:*属性设置特定属性的值。

<form action="subscribe.html" th:action="@{/subscribe}">

<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>

th:alt-title:将同时设置alttitle

th:lang-xmllang:将同时设置langxml:lang

<img src="../../images/gtvglogo.png" 
     th:src="@{/images/gtvglogo.png}" th:alt-title="#{logo}" />

//等同于
<img src="../../images/gtvglogo.png" 
     th:src="@{/images/gtvglogo.png}" th:title="#{logo}" th:alt="#{logo}" />

5.5th:class、th:classappend、th:styleappend

th:class:向元素添加class。

th:classappend:向元素已有class附加 CSS 类。

th:styleappend:向元素附加 style 样式。

<tr th:each="prod : ${prods}" class="row" th:classappend="${prodStat.odd}? 'odd'">

5.6th:checked

th:checked:固定值布尔属性。

<input type="checkbox" name="option2" checked /> <!-- HTML -->
<input type="checkbox" name="option1" checked="checked" /> <!-- XHTML -->
<input type="checkbox" name="active" th:checked="${user.active}" />

5.7th:each

5.7.1不带状态变量

${prods}:iterated expression 或 iterated variable。

prod:iteration variable 或 simply iter variable。

<tr th:each="prod : ${prods}">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>

5.7.2带状态变量

状态变量在th:each属性中定义并包含以下数据:

  • 当前迭代索引,从 0 开始。这是index属性。
  • 当前迭代索引,从 1 开始。这是count属性。
  • 迭代变量中的元素总数。这是size属性。
  • 每次迭代的 iter 变量。这是current属性。
  • 当前迭代是偶数(even)还是奇数(odd)。这些是even/odd布尔属性。
  • 当前迭代是否是第一个。这是first布尔属性。
  • 当前迭代是否是最后一个。这是last布尔属性。
<table>
  <tr>
    <th>NAME</th>
    <th>PRICE</th>
    <th>IN STOCK</th>
  </tr>
  <tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  </tr>
</table>

//省略iterStat,使用prodStat
<table>
  <tr>
    <th>NAME</th>
    <th>PRICE</th>
    <th>IN STOCK</th>
  </tr>
  <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  </tr>
</table>

//odd只为奇数行建立 CSS 类
//都输出
<table>
    <tr>
        <th>NAME</th>
        <th>PRICE</th>
        <th>IN STOCK</th>
    </tr>
    <tr class="odd">
        <td>Fresh Sweet Basil</td>
        <td>4.99</td>
        <td>yes</td>
    </tr>
    <tr>
        <td>Italian Tomato</td>
        <td>1.25</td>
        <td>no</td>
    </tr>
    <tr class="odd">
        <td>Yellow Bell Pepper</td>
        <td>2.50</td>
        <td>yes</td>
    </tr>
    <tr>
        <td>Old Cheddar</td>
        <td>18.75</td>
        <td>yes</td>
    </tr>
</table>

5.8th:if、th:unless、th:switch

th:if属性不仅仅会计算布尔条件,支持的表达式如下:

  • 如果值不为null
    • 如果值是一个布尔值并且是true
    • 如果值是一个数字并且非零
    • 如果值是一个字符并且非零
    • 如果值是一个字符串并且不是“false”“off”“no”
    • 如果值不是布尔值、数字、字符或字符串。
  • 如果值为nullth:if 将计算为 false
<table>
  <tr>
    <th>NAME</th>
    <th>PRICE</th>
    <th>IN STOCK</th>
    <th>COMMENTS</th>
  </tr>
  <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
    <td>
      <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
      <a href="comments.html" 
         th:href="@{/product/comments(prodId=${prod.id})}" 
         th:if="${not #lists.isEmpty(prod.comments)}">view</a>
    </td>
  </tr>
</table>

//输出
<table>
  <tr>
    <th>NAME</th>
    <th>PRICE</th>
    <th>IN STOCK</th>
    <th>COMMENTS</th>
  </tr>
  <tr class="odd">
    <td>Fresh Sweet Basil</td>
    <td>4.99</td>
    <td>yes</td>
    <td>
      <span>0</span> comment/s
    </td>
  </tr>
  <tr>
    <td>Italian Tomato</td>
    <td>1.25</td>
    <td>no</td>
    <td>
      <span>2</span> comment/s
      <a href="/gtvg/product/comments?prodId=2">view</a>
    </td>
  </tr>
  <tr class="odd">
    <td>Yellow Bell Pepper</td>
    <td>2.50</td>
    <td>yes</td>
    <td>
      <span>0</span> comment/s
    </td>
  </tr>
  <tr>
    <td>Old Cheddar</td>
    <td>18.75</td>
    <td>yes</td>
    <td>
      <span>1</span> comment/s
      <a href="/gtvg/product/comments?prodId=4">view</a>
    </td>
  </tr>
</table>

th:unlessth:if的逆属性。

<a href="comments.html"
    th:href="@{/comments(prodId=${prod.id})}" 
    th:unless="${#lists.isEmpty(prod.comments)}">view</a>

th:switch:等效于switch-case条件。

默认选项指定为th:case="*"

<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
  <p th:case="*">User is some other thing</p>
</div>

5.9th:fragment、th:insert、th:replace、th:with、th:block

5.9.1不带参数的片段

th:fragment:声明片段。

//footer.html
//创建片段
<!DOCTYPE html>

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

    <body>
    
        //th:fragment语法
        <div th:fragment="copy">
            &copy; 2011 The Good Thymes Virtual Grocery
        </div>
 
        //id选择器语法
        <div id="copy-section">
            &copy; 2011 The Good Thymes Virtual Grocery
        </div>
  
  </body>
  
</html>
<body>

  ...
  //通过th:fragment引入片段
  <div th:insert="~{footer :: copy}"></div>
  //通过id选择器引入片段
  <div th:insert="~{footer :: #copy-section}"></div>

</body>

th:insert:引入片段作为元素的内容。

th:replace:引入片段替代整个元素。

<footer th:fragment="copy">
  &copy; 2011 The Good Thymes Virtual Grocery
</footer>
<body>

  ...

  <div th:insert="footer :: copy"></div>

  <div th:replace="footer :: copy"></div>
  
</body>
//输出
<body>

  ...

  <div>
    <footer>
      &copy; 2011 The Good Thymes Virtual Grocery
    </footer>
  </div>

  <footer>
    &copy; 2011 The Good Thymes Virtual Grocery
  </footer>
  
</body>

5.9.2带参数的片段

th:with:声明局部变量。

//显式参数
<div th:fragment="frag (onevar,twovar)">
    <p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>

//引入支持按位置和按命名传递参数
<div th:replace="::frag (${value1},${value2})">...</div>
<div th:replace="::frag (onevar=${value1},twovar=${value2})">...</div>
<div th:replace="::frag (twovar=${value2},onevar=${value1})">...</div>
//隐式参数
<div th:fragment="frag">
    <p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>

//引入只支持按命名传递参数
<div th:replace="::frag (onevar=${value1},twovar=${value2})">...</div>
<div th:replace="::frag (twovar=${value2},onevar=${value1})">...</div>
//按命名传递参数等同于th:replace 和 th:with 的组合
<div th:replace="::frag" th:with="onevar=${value1},twovar=${value2}">

5.9.3模板布局

th:block:只是一个属性容器,它允许模板开发人员指定他们想要的任何属性。

//base.html
//创建片段
<head th:fragment="common_header(title,links)">

  <title th:replace="${title}">The awesome application</title>

  <!-- Common styles and scripts -->
  <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}">
  <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
  <script type="text/javascript" th:src="@{/sh/scripts/codebase.js}"></script>

  <!--/* Per-page placeholder for additional links */-->
  <th:block th:replace="${links}" />

</head>
//引入片段
<head th:replace="base :: common_header(~{::title},~{::link})">

  <title>Awesome - Main</title>

  <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
  <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">

</head>
//输出
<head>

  <title>Awesome - Main</title>

  <!-- Common styles and scripts -->
  <link rel="stylesheet" type="text/css" media="all" href="/awe/css/awesomeapp.css">
  <link rel="shortcut icon" href="/awe/images/favicon.ico">
  <script type="text/javascript" src="/awe/sh/scripts/codebase.js"></script>

  <link rel="stylesheet" href="/awe/css/bootstrap.min.css">
  <link rel="stylesheet" href="/awe/themes/smoothness/jquery-ui.css">

</head>

5.9.4布局继承

<!DOCTYPE html>
<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:replace="${title}">Layout Title</title>
</head>
<body>
    <h1>Layout H1</h1>
    <div th:replace="${content}">
        <p>Layout content</p>
    </div>
    <footer>
        Layout footer
    </footer>
</body>
</html>
<!DOCTYPE html>
<html th:replace="~{layoutFile :: layout(~{::title}, ~{::section})}">
<head>
    <title>Page Title</title>
</head>
<body>
<section>
    <p>Page content</p>
    <div>Included on page</div>
</section>
</body>
</html>

5.10th:assert

th:assert:指定一个逗号分隔的表达式列表,这些表达式应该被计算并为每次计算产生 true,如果不是则引发异常。

<div th:assert="${onevar},(${twovar} != 43)">...</div>

这对于验证片段签名中的参数非常有用。

<header th:fragment="contentheader(title)" th:assert="${!#strings.isEmpty(title)}">...</header>

6.表单

6.1<form>

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

6.2<input type=”text”>

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

6.3<input type=”radio”>

<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>

6.4<input type=”checkbox”>

//单值复选框
<div>
  <label th:for="${#ids.next('covered')}" th:text="#{seedstarter.covered}">Covered</label>
  <input type="checkbox" th:field="*{covered}" />
</div>
//多值复选框
<ul>
  <li th:each="feat : ${allFeatures}">
    <input type="checkbox" th:field="*{features}" th:value="${feat}" />
    <label th:for="${#ids.prev('features')}" 
           th:text="#{${'seedstarter.feature.' + feat}}">Heating</label>
  </li>
</ul>

//输出
<ul>
  <li>
    <input id="features1" name="features" type="checkbox" value="SEEDSTARTER_SPECIFIC_SUBSTRATE" />
    <input name="_features" type="hidden" value="on" />
    <label for="features1">Seed starter-specific substrate</label>
  </li>
  <li>
    <input id="features2" name="features" type="checkbox" value="FERTILIZER" />
    <input name="_features" type="hidden" value="on" />
    <label for="features2">Fertilizer used</label>
  </li>
  <li>
    <input id="features3" name="features" type="checkbox" value="PH_CORRECTOR" />
    <input name="_features" type="hidden" value="on" />
    <label for="features3">PH Corrector used</label>
  </li>
</ul>

6.5<select>

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

7.验证和错误消息

7.1字段错误

#fields.hasErrors():函数接收字段表达式作为参数 ( datePlanted),并返回一个布尔值,告知该字段是否存在任何验证错误。

#fields.errors():函数接收字段表达式作为参数 ( datePlanted),并返回该字段的所有错误。

//配置CSS类
<input type="text" th:field="*{datePlanted}" 
                   th:class="${#fields.hasErrors('datePlanted')}? fieldError" />
//显示错误
<ul th:if="${#fields.hasErrors('datePlanted')}>
  <li th:each="err : ${#fields.errors('datePlanted')}" th:text="${err}" />
</ul>

th:errorclass:一个专门的属性,目的是简化上面的th:class,可以将特定的 CSS 类设置给字段。

th:errors:一个专门的属性,目的是简化上面的th:each,它构建一个列表,其中包含指定选择器的所有错误,由<br />分隔。

//配置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" />
//显示错误
<p th:if="${#fields.hasErrors('datePlanted')}" th:errors="*{datePlanted}">Incorrect date</p>

7.2所有错误

#fields.hasErrors('*')等价于#fields.hasErrors('all')#fields.hasAnyErrors()

#fields.errors('*')等价于#fields.errors('all')#fields.allErrors()

//显示错误(th:each方式)
<ul th:if="${#fields.hasErrors('*')}">
  <li th:each="err : ${#fields.errors('*')}" th:text="${err}">Input is incorrect</li>
</ul>
//显示错误(th:errors简化方式)
<p th:if="${#fields.hasErrors('all')}" th:errors="*{all}">Incorrect date</p>

7.3全局错误

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

#fields.hasErrors('global')等价于#fields.hasGlobalErrors()

#fields.errors('global')等价于#fields.globalErrors()

//显示错误(th:each方式)
<ul th:if="${#fields.hasErrors('global')}">
  <li th:each="err : ${#fields.errors('global')}" th:text="${err}">Input is incorrect</li>
</ul>
//显示错误(th:errors简化方式)
<p th:if="${#fields.hasErrors('global')}" th:errors="*{global}">Incorrect date</p>

原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/java/springboot/16783.html

(0)
上一篇 2022年8月3日 00:52
下一篇 2022年8月4日 00:54

相关推荐

发表回复

登录后才能评论