Thymeleaf

Thymeleaf

  • Java模版引擎:Thymeleaf是一个用于Web和独立环境的现代服务器端Java模板引擎。能够处理HTML、XML、JavaScript、CSS甚至纯文本。
  • 自然模板:Thymeleaf的主要目标是为您的开发工作流程带来优雅的自然模板——HTML,它可以在浏览器中正确显示,也可以作为静态原型工作(原型即界面),改善了设计与开发的沟通,从而在开发团队中实现更强的协作。
  • 语法优雅易懂:
  • 遵从web标准,支持HTML5

Thymeleaf 使用

一、标准方言

秉着“开箱即用”的原则,Thymeleaf提供了满足大多数情况下的默认实现-标准方言(后面会介绍自定义方言):

  1. 引入标签库(命名空间), 需要引入命名空间<html xmlns:th="http://www.thymeleaf.org">  Html代码  [收藏代码](javascript:void())

  2. HTML5标准,自定义属性:

    <table>  
        <tr data-th-each="user : ${users}">  
            <td data-th-text="${user.login}">...</td>  
            <td data-th-text="${user.name}">...</td>  
        </tr>  
    </table>  
    
    
    

    这样可以省去命名空间

Thymeleaf基本语法

标准表达式

变量表达式

  • 语法:${...}
  • 用法:<p th:text="${book.author}"></p>

消息表达式

  • 语法:#{...}

  • 用法: 相当于消息的一个key,也称文本外部化,一般用于国际化等外部配置文件,其中properties文件内容为Java代码 home.welcome=welcome to thymeleaf , 目前消息文件中的内容是固定的,如果我们需要向消息中动态插入一个参数以便实现动态消息,可以用     #{messageKey(param=value)},多个参数用','分割 ,#{messageKey(param1=value1, param2=value2)},messageKey本身也可以是一个变量表达式:<p th:text="#{home.welcome}">Welcome to our grocery store!</p>

    home.welcome=welcome to {0}
    
    
    
    <p th:utext="#{home.welcome(${session.user.name})}">   
           Welcome to our grocery store, Sebastian Pepper!   
    </p>  
      
    <p th:utext="#{${welcomeMsgKey}(${session.user.name})}">  
      Welcome to our grocery store, Sebastian Pepper!  
    </p>  
    
    
    

大多数情况下, 消息源是.properties文件,同时可以自定义其他消息源,比如数据库。消息源通过org.thymeleaf.messageresolver.IMessageResolver获取,如果在初始化模板引擎时没有自定义的IMessageResolver被提供,那么一个默认的实现org.thymeleaf.messageresolver.StandardMessageResolver会被自动提供。

StandardMessageResolver查找和模板文件位于同级目录,且具有和模板文件相同名字的.properties文件。

模板/templates/home.html在渲染时,会根据local设置,使用下面的消息源文件

  • /templates/home_zh_CN.properties --->中文
  • /templates/home_en.properties --->英文
  • /templates/home.properties 如--->特定的lcoal不可用时使用

在spring boot中,默认去寻找resources下面名为messages的properties文件,可以通过spring.messages.basename进行修改

选择表达

  • 语法:*{...}

  • 示例:

    <div th:object="${session.book}">  
        <p>Name: <span th:text="*{title}">thymeleaf实战</span>.</p>  
        <p>Surname: <span th:text="*{author}">Peppa</span>.</p>  
        <p>Nationality: <span th:text="*{price}">300</span>.</p>  
      </div>  
    
    
    

与变量表达式的区别:它们是在当前选择的对象而不是整个上下文变量映射上执行(性能高)

链接表达式

  • 语法:@{...}

  • 示例

  • 绝对url:<a th:href="@{http://www.thymeleaf.org}" th:text="">...</>

  • 相对url,可以是:

    • 相对url: user/login.html
    • 上下文相对: /user/login.do (自动添加服务器中的应用上下文名称)
    • 服务器相对: ~/billing/processInvoice (允许在同一服务器的另一个上下文(=应用程序)中调用URL).
    • 协议相对: //code.jquery.com/jquery-2.0.3.min.js

在链接中使用参数(变量)<a href="details.html" th:href="@{/order/details(orderId=${o.id},orderType=${o.type})}">view</a>
RESTful风格:<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${orderId})}">view</a>

片段表达式

片段表达式是表示标记片段并围绕模板移动它们的简单方法。这允许我们复制它们,将它们作为参数传递给其他模板,等等

  • 语法:~{...}

  • 示例 : <div th:insert="~{commons :: footer}">...</div>

    使用th:insert or th:replace插入片段,它们可以在任何地方使用,就像任何其他变量一样:

    <div th:with="frag=~{footer :: #footer/text()}">  
      <p th:insert="${frag}">  
    </div>
    
    
    
    Thymeleaf字面量
  • 文本字面量:

    <p th:text="'<h1>我是一个香蕉,蕉蕉蕉蕉蕉蕉</h1>'"</p>  
    <p th:utext="'<h1>我是一个香蕉,蕉蕉蕉蕉蕉蕉</h1>'"</p>    
    
    
    
    • 区别:th:text对html标签转义,th:utext不转义,解析为html内容
    • 数字字面量: 0343.012.3,…
    • Boolean 字面量: truefalse
    • Null 值字面量: null
    • 文字标记: onesometextmain,…(不需要单引号'',这些令牌允许在标准表达式中进行一点简化。它们的工作与文本文字('...')完全相同,但它们只允许使用字母(A-Za-z),数字(0-9),括号([]),点(.),连字符(-)和下划线(_)。所以没有空白,没有逗号等)
  • 文本操作:

    • 字符串连接: +
    • 文字替换: |The name is ${name}|
  • 算术运算符:

    • 二元运算符: +-*/%
    • 减号(一元运算): -
  • 逻辑运算符:

    • 二元运算符: andor
    • 逻辑非(一元运算符): !not
  • 比较运算符:

    • 比较运算符: ><>=<= (gtltgele)
    • 相等比较: ==!= (eqne)
  • 条件运算符:

    • If-then: (if) ? (then)
    • If-then-else: (if) ? (then) : (else)
    • Default: (value) ?: (defaultvalue)
  • Special tokens:

    • No-Operation(无操作): _          如果条件不满足,保留在原型中定义的值(文本)
<p th:utext="${user.username}?:_">我是原型的值</p>



设置属性值

  • Java模版引擎:Thymeleaf是一个用于Web和独立环境的现代服务器端Java模板引擎。能够处理

  • 设置任意属性值-->th:attr

    <form action="subscribe.html" th:attr="action=@{/subscribe}">  
      <fieldset>  
        <input type="text" name="email" />  
        <input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>  
      </fieldset>  
    </form>
    
    
    
  • 设置值到指定的属性---->HTML5标签的常用属性。

    <input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>  
    <form action="subscribe.html" th:action="@{/subscribe}">  
    <li><a href="product/list.html" th:href="@{/product/list}">Product List</a></li>  
    
    
    
  • 固定值布尔属性---->属性就代表值  <input type="checkbox" name="active" th:checked="${user.active}" />

迭代器

  • 基本的迭代---->th:each

    1. <li th:each="book:${books}" th:text="${book.title}"></li>
    • ${books}为迭代变量(作用域中的Iterable,Enumeration,Iterator,Map,Entry,Array及字符串等,相当于标准标签库中<c:forEach>里的items属性
    • book为当前迭代的元素,相当于var属性
  • 状态变量:跟踪迭代器的状态(相当于标准标签库的varStatus标签)

    <table>
    <tr>
    <th>NAME</th>
    </tr>
    <tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
    <td th:text=" #{prod.name}"></td>
    </tr>
    </table>
    index:当前迭代索引,从0开始。
    count:当前迭代索引,从1开始。
    size:迭代变量中元素的总数。
    current:每个迭代的ITER变量。
    even/odd:当前迭代是偶数还是奇数。
    first:当前迭代是否为第一个元素。
    last:当前迭代是否为最后一个元素。
  • 条件语句

  • th:if

    <a href="comments.html"  
       th:href="@{/product/comments(prodId=${prod.id})}"   
       th:if="${not #lists.isEmpty(prod.comments)}">view
    </a>  
  • th:unless---->条件不成立

    <a href="comments.html"
    th:href="@{/comments(prodId=${prod.id})}"
    th:unless="${#lists.isEmpty(prod.comments)}">view</a>
  • th:switch/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>
  • 模板布局

  • 在我们的模板中,我们通常希望包括来自其他模板的部件,如页脚、页眉、菜单等部件(公共部分);或是固定的模板格式渲染成不同的内容,如邮件模板,商品详情页模板…
    为了做到这一点,thymeleaf需要我们定义这些部分,“片段”,以便包含,这可以使用th:fragment属性完成。
    假设我们想在所有杂货店页面中添加一个标准的版权页脚,那么我们创建一个/templates/footer.html文件,其中包含以下代码:

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <body>
    <div th:fragment="copy">
    © 2011 The Good Thymes Virtual Grocery
    </div>
    </body>
    </html>

    使用th:insert或者th:replace插入片段,th:include只插入片段内容(不推荐使用)Java代码

    <body>
    ...
    <div th:insert="~{footer :: copy}"></div>
    </body>

    其中footer为模板名称,copy为片段名称,也可以不使用th:fragment,使用格式如下

    <div id="copy-section">
    © 2011 The Good Thymes Virtual Grocery
    </div>
    ...
    <body>
    ...
    <div th:insert="~{footer :: #copy-section}"></div>
    </body>
  • 注释

  • 标准html/xml注释

  • thymeleaf解析器级注释Java代码  

    <!--/* 
      <div th:text="${...}"> 
        ... 
      </div> 
    */-->  
  • 原型注释块[静态时注释,模板执行时显示

  • 内联

  • 直接将表达式写在文本中而非标签中,js,css中使用常见Js代码 

    script th:inline="javascript">
    ...
    var username = [[${session.user.name}]];
    ...
    </script>
  • 格式:[[...]]或者[(...)]分别对应th:text和th:utext

  • 禁用内联---->th:inline="none"

  • 表达式基本对象(隐式对象,存在于上下文中)

  • #ctx:上下文对

    ${#ctx.request}  
    ${#ctx.response}  
    ${#ctx.session}  
    ${#ctx.servletContext}

     

  • #locale:直接访问与java.util.Locale关联的当前请求 

    ${#locale}
  • param,获取请求相关的属性,如请求参数,request.getParmeter("")等Java代码 

    ${param.size()}
    ${param.isEmpty()}
    ${param.containsKey('...')}
  • session : 获取存在session中的变量

    ${session.size()}  
    ${session.isEmpty()}  
    ${session.containsKey('foo')} 
  • application : 获取存在application中的变量

    ${application.size()}
    ${application.isEmpty()}
    ${application.containsKey('foo')}
  • Web 上下文对象

    • #servletContext : `javax.servlet.ServletContext`

      ${#servletContext.getAttribute('foo')}
      ${#servletContext.contextPath}
    • #session : `javax.servlet.http.HttpSession`

      ${#session.getAttribute('foo')}
      ${#session.id}
      ${#session.lastAccessedTime}
    • #request : 当前请求javax.servlet.http.HttpServletRequest 

      ${#request.getAttribute('foo')}
      ${#request.getParameter('foo')}
      ${#request.getContextPath()}
    • 标准方言中包含的thymeleaf的唯一元素处理器(不是属性)是th:block。
      th:block是一个属性容器,允许模板开发人员指定他们想要的属性。thymeleaf将执行这些属性,然后简单地使块(而不是其内容)消失。
      因此,它可能很有用,例如,当创建迭代表时,每个元素需要一个以上的<tr>,或者需要条件判断时

      <table>
      th:block th:each="user : ${users}"
      <tr>
      <td th:text="${user.login}">...</td>
      <td th:text="${user.name}">...</td>
      </tr>
      <tr>
      <td colspan="2" th:text="${user.address}">...</td>
      </tr>
      </th:block>
      </table>

实用对象

      这些使用表达式对象在package org.thymeleaf.expression包下都有对应的类,如果不知道怎么使用直接看Javadoc就好,推荐使用的时候按需查询。

  • #messages : 用于在变量表达式中获得外部消息的实用方法,与使用#{…}语法获得的方式相同
    ${#messages.msg('msgKey')}
    ${#messages.msg('msgKey', param1)}
    ${#messages.msg('msgKey', param1, param2)}
    ${#messages.arrayMsg(messageKeyArray)}
    ${#messages.listMsg(messageKeyList)}
    ${#messages.setMsg(messageKeySet)}
    ${#messages.msgOrNull('msgKey')}
    ${#messages.msgOrNull('msgKey', param1)}
    ${#messages.arrayMsgOrNull(messageKeyArray)}
    ${#messages.listMsgOrNull(messageKeyList)}
    ${#messages.setMsgOrNull(messageKeySet)}
  • #uris : 用于在Thymeleaf标准表达式中执行URI / URL操作(特别是转义/消除转义)的实用对象
    ${#uris.escapePath(uri)}
    ${#uris.escapePath(uri, encoding)}
    ${#uris.unescapePath(uri)}
    ${#uris.unescapePath(uri, encoding)}
    ${#uris.escapePathSegment(uri)}
    ${#uris.escapePathSegment(uri, encoding)}
    ${#uris.unescapePathSegment(uri)}
    ${#uris.unescapePathSegment(uri, encoding)}
    ${#uris.escapeFragmentId(uri)}
    ${#uris.escapeFragmentId(uri, encoding)}
    ${#uris.unescapeFragmentId(uri)}
    ${#uris.unescapeFragmentId(uri, encoding)}
    ${#uris.escapeQueryParam(uri)}
    ${#uris.escapeQueryParam(uri, encoding)}
    ${#uris.unescapeQueryParam(uri)}
    ${#uris.unescapeQueryParam(uri, encoding)}
  • #conversions : 允许在模板的任意位置执行转换服务的实用程序对象:
    ${#conversions.convert(object, 'java.util.TimeZone')}
    ${#conversions.convert(object, targetClass)}
  • #dates : 为 java.util.Date对象提供工具方法,比如:格式化,提取年月日等
    ${#dates.format(date)}
    ${#dates.arrayFormat(datesArray)}
    ${#dates.listFormat(datesList)}
    ${#dates.setFormat(datesSet)}
    ${#dates.formatISO(date)}
    ${#dates.arrayFormatISO(datesArray)}
    ${#dates.listFormatISO(datesList)}
    ${#dates.setFormatISO(datesSet)}
    ${#dates.format(date, 'dd/MMM/yyyy HH:mm')}
    ${#dates.arrayFormat(datesArray, 'dd/MMM/yyyy HH:mm')}
    ${#dates.listFormat(datesList, 'dd/MMM/yyyy HH:mm')}
    ${#dates.setFormat(datesSet, 'dd/MMM/yyyy HH:mm')}
    ${#dates.day(date)}                    // also arrayDay(...), listDay(...), etc.
    ${#dates.month(date)}                  // also arrayMonth(...), listMonth(...), etc.
    ${#dates.monthName(date)}              // also arrayMonthName(...), listMonthName(...), etc.
    ${#dates.monthNameShort(date)}         // also arrayMonthNameShort(...), listMonthNameShort(...), etc.
    ${#dates.year(date)}                   // also arrayYear(...), listYear(...), etc.
    ${#dates.dayOfWeek(date)}              // also arrayDayOfWeek(...), listDayOfWeek(...), etc.
    ${#dates.dayOfWeekName(date)}          // also arrayDayOfWeekName(...), listDayOfWeekName(...), etc.
    ${#dates.dayOfWeekNameShort(date)}     // also arrayDayOfWeekNameShort(...), listDayOfWeekNameShort(...), etc.
    ${#dates.hour(date)}                   // also arrayHour(...), listHour(...), etc.
    ${#dates.minute(date)}                 // also arrayMinute(...), listMinute(...), etc.
    ${#dates.second(date)}                 // also arraySecond(...), listSecond(...), etc.
    ${#dates.millisecond(date)}            // also arrayMillisecond(...), listMillisecond(...), etc.
    ${#dates.create(year,month,day)}
    ${#dates.create(year,month,day,hour,minute)}
    ${#dates.create(year,month,day,hour,minute,second)}
    ${#dates.create(year,month,day,hour,minute,second,millisecond)}
    ${#dates.createNow()}
    ${#dates.createNowForTimeZone()}
    ${#dates.createToday()}
    ${#dates.createTodayForTimeZone()}

     

  • #calendars : 类似于#dates , 但是只针对java.util.Calendar对象
    ${#calendars.format(cal)}
    ${#calendars.arrayFormat(calArray)}
    ${#calendars.listFormat(calList)}
    ${#calendars.setFormat(calSet)}
    ${#calendars.formatISO(cal)}
    ${#calendars.arrayFormatISO(calArray)}
    ${#calendars.listFormatISO(calList)}
    ${#calendars.setFormatISO(calSet)}
    ${#calendars.format(cal, 'dd/MMM/yyyy HH:mm')}
    ${#calendars.arrayFormat(calArray, 'dd/MMM/yyyy HH:mm')}
    ${#calendars.listFormat(calList, 'dd/MMM/yyyy HH:mm')}
    ${#calendars.setFormat(calSet, 'dd/MMM/yyyy HH:mm')}
    ${#calendars.day(date)}                // also arrayDay(...), listDay(...), etc.
    ${#calendars.month(date)}              // also arrayMonth(...), listMonth(...), etc.
    ${#calendars.monthName(date)}          // also arrayMonthName(...), listMonthName(...), etc.
    ${#calendars.monthNameShort(date)}     // also arrayMonthNameShort(...), listMonthNameShort(...), etc.
    ${#calendars.year(date)}               // also arrayYear(...), listYear(...), etc.
    ${#calendars.dayOfWeek(date)}          // also arrayDayOfWeek(...), listDayOfWeek(...), etc.
    ${#calendars.dayOfWeekName(date)}      // also arrayDayOfWeekName(...), listDayOfWeekName(...), etc.
    ${#calendars.dayOfWeekNameShort(date)} // also arrayDayOfWeekNameShort(...), listDayOfWeekNameShort(...), etc.
    ${#calendars.hour(date)}               // also arrayHour(...), listHour(...), etc.
    ${#calendars.minute(date)}             // also arrayMinute(...), listMinute(...), etc.
    ${#calendars.second(date)}             // also arraySecond(...), listSecond(...), etc.
    ${#calendars.millisecond(date)}        // also arrayMillisecond(...), listMillisecond(...), etc.
    ${#calendars.create(year,month,day)}
    ${#calendars.create(year,month,day,hour,minute)}
    ${#calendars.create(year,month,day,hour,minute,second)}
    ${#calendars.create(year,month,day,hour,minute,second,millisecond)}
    ${#calendars.createForTimeZone(year,month,day,timeZone)}
    ${#calendars.createForTimeZone(year,month,day,hour,minute,timeZone)}
    ${#calendars.createForTimeZone(year,month,day,hour,minute,second,timeZone)}
    ${#calendars.createForTimeZone(year,month,day,hour,minute,second,millisecond,timeZone)}
    ${#calendars.createNow()}
    ${#calendars.createNowForTimeZone()}
    ${#calendars.createToday()}
    ${#calendars.createTodayForTimeZone()}

     

  • #numbers : 为数值型对象提供工具方法
    ${#numbers.formatInteger(num,3)}
    ${#numbers.arrayFormatInteger(numArray,3)}
    ${#numbers.listFormatInteger(numList,3)}
    ${#numbers.setFormatInteger(numSet,3)}
    ${#numbers.formatInteger(num,3,'POINT')}
    ${#numbers.arrayFormatInteger(numArray,3,'POINT')}
    ${#numbers.listFormatInteger(numList,3,'POINT')}
    ${#numbers.setFormatInteger(numSet,3,'POINT')}
    ${#numbers.formatDecimal(num,3,2)}
    ${#numbers.arrayFormatDecimal(numArray,3,2)}
    ${#numbers.listFormatDecimal(numList,3,2)}
    ${#numbers.setFormatDecimal(numSet,3,2)}
    ${#numbers.formatDecimal(num,3,2,'COMMA')}
    ${#numbers.arrayFormatDecimal(numArray,3,2,'COMMA')}
    ${#numbers.listFormatDecimal(numList,3,2,'COMMA')}
    ${#numbers.setFormatDecimal(numSet,3,2,'COMMA')}
    ${#numbers.formatDecimal(num,3,'POINT',2,'COMMA')}
    ${#numbers.arrayFormatDecimal(numArray,3,'POINT',2,'COMMA')}
    ${#numbers.listFormatDecimal(numList,3,'POINT',2,'COMMA')}
    ${#numbers.setFormatDecimal(numSet,3,'POINT',2,'COMMA')}
    ${#numbers.formatCurrency(num)}
    ${#numbers.arrayFormatCurrency(numArray)}
    ${#numbers.listFormatCurrency(numList)}
    ${#numbers.setFormatCurrency(numSet)}
    ${#numbers.formatPercent(num)}
    ${#numbers.arrayFormatPercent(numArray)}
    ${#numbers.listFormatPercent(numList)}
    ${#numbers.setFormatPercent(numSet)}
    ${#numbers.formatPercent(num, 3, 2)}
    ${#numbers.arrayFormatPercent(numArray, 3, 2)}
    ${#numbers.listFormatPercent(numList, 3, 2)}
    ${#numbers.setFormatPercent(numSet, 3, 2)}
    ${#numbers.sequence(from,to)}
    ${#numbers.sequence(from,to,step)}

     

  • #strings : 为String 对象提供工具方法。如: contains, startsWith, prepending/appending等:
  • #objects : 为object 对象提供常用的工具方法
    ${#objects.nullSafe(obj,default)}
    ${#objects.arrayNullSafe(objArray,default)}
    ${#objects.listNullSafe(objList,default)}
    ${#objects.setNullSafe(objSet,default)}
  • #bools : 为boolean 对象提供常用的工具方法
  • #arrays : 为arrays 对象提供常用的工具方法
    ${#arrays.toArray(object)}
    ${#arrays.toStringArray(object)}
    ${#arrays.toIntegerArray(object)}
    ${#arrays.toLongArray(object)}
    ${#arrays.toDoubleArray(object)}
    ${#arrays.toFloatArray(object)}
    ${#arrays.toBooleanArray(object)}
    ${#arrays.length(array)}
    ${#arrays.isEmpty(array)}
    ${#arrays.contains(array, element)}
    ${#arrays.containsAll(array, elements)}
  • #lists :为lists对象提供常用的工具方法
    ${#lists.toList(object)}
    ${#lists.size(list)}
    ${#lists.contains(list, element)}
    ${#lists.containsAll(list, elements)}
    ${#lists.sort(list)}
    ${#lists.sort(list, comparator)}
  • #sets : 为lists对象提供常用的工具方法
    ${#sets.toSet(object)}
    ${#sets.size(set)}
    ${#sets.isEmpty(set)}
    ${#sets.contains(set, element)}
    ${#sets.containsAll(set, elements)}
  • #maps : 为lists对象提供常用的工具方法
    ${#maps.size(map)}
    ${#maps.isEmpty(map)}
    ${#maps.containsKey(map, key)}
    ${#maps.containsAllKeys(map, keys)}
    ${#maps.containsValue(map, value)}
    ${#maps.containsAllValues(map, value)}
  • #aggregates : 为创造一个arrays 或者 collections聚集函数提供常用的工具方法
    ${#aggregates.sum(array)}
    ${#aggregates.sum(collection)}
    ${#aggregates.avg(array)}
    ${#aggregates.avg(collection)}
  • #ids :为可能需要循环的ID属性提供常用的工具方法
    ${#ids.seq('someId')}
    ${#ids.next('someId')}
    ${#ids.prev('someId')}

     

转载于:https://my.oschina.net/u/4134962/blog/3071495

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值