zoukankan      html  css  js  c++  java
  • Thymeleaf

    th:text及外化文本

    外化文本把模板代码从模板文件抽取出来,独立放到特定的文件中,例如.properties文件,可以很方便地替换为不同语言的文本表示,外化文本通常叫做消息。

    使用#{…}来引用消息

    模板文件与属性文件必须要放在同一个目录下,且文件名也要符合规范:

    /WEB-INF/templates/home.html

    /WEB-INF/templates/home_en.properties

    /WEB-INF/templates/home_es.properties

    /WEB-INF/templates/home_pt_BR.properties

    /WEB-INF/templates/home.properties

     

    可对消息使用参数:

    home.welcome=¡Bienvenido a nuestra tienda de comestibles, {0}!
     
    消息的参数根据java.text.MessageFormat标准语法来指定:
    <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>

     

    上下文

    上下文是实现接口org.thymeleaf.context.IContext的对象,它把所有模板引擎执行需要的数据包含在一个Map变量中,同时引用用于处理外化文本的Locale。

    org.thymeleaf.context.IWebContext继承了org.thymeleaf.context.IContext:

    public interface IWebContext extends IContext {
        
        public HttpSerlvetRequest getHttpServletRequest();
        public HttpSession getHttpSession();
        public ServletContext getServletContext();
        
        public VariablesMap<String,String[]> getRequestParameters();
        public VariablesMap<String,Object> getRequestAttributes();
        public VariablesMap<String,Object> getSessionAttributes();
        public VariablesMap<String,Object> getApplicationAttributes();
        
    }
     
    它们的实现有两个:
    • org.thymeleaf.context.Context implements IContext
    • org.thymeleaf.context.WebContext implements IWebContext

     

    WebContext比Context多做的工作有:

    把所有请求属性添加到上下文map变量中

    添加包含所有请求参数的param上下文变量

    添加包含所有会话属性的session上下文变量

    添加包含所有ServletContext属性的application上下文变量

     

    在执行模板解析前,会设置一个叫执行信息(exeInfo)的特殊变量到所有的上下文对象(实现IContext接口,包括Context和WebContext)中,这个变量有两个可在模板中使用的数据:

    ${execInfo.templateName} 模板名称

    ${execInfo.now} 一个Calendar对象,表示引擎开始执行模板的时间

     

    保留文本原样

    th:text标签默认会对标签内的特殊字符做转义处理

    th:utext标签可以让标签值中的内容按原样输出

     

    使用变量

    ${…}会基于上下文的map变量执行,从map变量中使用OGNL语言获取变量值。

    ${person.father.name}
    
    ${person['father']['name']}
    ${countriesByCode.ES}
    ${personsByName['Stephen Zucchini'].age}
    ${personsArray[0].name}
    ${person.createCompleteName()}
    ${person.createCompleteNameWithSeparator('-')}
     
    在上下文变量上执行OGNL表达式时,有一些对象在表达式上是可用的,可通过使用#来引用:
    • #ctx 上下文对象
    • #vars 上下文变量
    • #locale 上下文locale
    • #httpServletRequest (仅Web上下文)HttpServletRequest对象
    • #httpSession (仅Web上下文)HttpSession对象

    例子:

    Established locale country: <span th:text="${#locale.country}">US</span>.
     
    变量表达式也可以写成*{…},所不同的是,星号语法会在一个选定的对象上进行运算,而不是在整个map上下文变量上运算。如果没有选定的对象,则${…}与*{…}所做的事情都是相同的。
     
    使用th:object来选定对象:
    <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>
     
    星号和美元可以混用:
    <div th:object="${session.user}">
      <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
      <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
      <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
    </div>
     
    当选定一个对象时,这个对象可以在${…}中通过#object表达式变量来引用:
    <div th:object="${session.user}">
      <p>Name: <span th:text="${#object.firstName}">Sebastian</span>.</p>
      <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
      <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
    </div>
     
    如果不选择对象,则两者是等价的:
    <div>
      <p>Name: <span th:text="*{session.user.name}">Sebastian</span>.</p>
      <p>Surname: <span th:text="*{session.user.surname}">Pepper</span>.</p>
      <p>Nationality: <span th:text="*{session.user.nationality}">Saturn</span>.</p>
    </div>
     
     
     

    标准表达式语法

    简单表达式

    • ${…} 变量表达式

    • *{…} 选择变量表达式

    • #{…} 消息表达式

    • @{…} 链接URL表达式

    字面量

    • 文本字面量:‘one text’

    <span th:text="'working web application'">template file</span>
    • 数字字面量:0,34,3.0

    <span th:text="2013 + 2">1494</span>
    • 布尔字面量:true,false

    == false”写在花括号外面,则比较操作由Thymeleaf标准表达式引擎处理
    <div th:if="${user.isAdmin()} == false"> ...
    == false”写在花括号里面,则由OGNL/SpEL引擎处理
    <div th:if="${user.isAdmin() == false}"> ...
     
    • Null字面量:null

    <div th:if="${variable.something} == null"> ...
    • 字面量标志:one,sometext,main,…

    数字、布尔、Null三种字面量实际上是字面量token的特例。

    这些token可以在标准表达式中得到一些简化,它们的工作原理与文本字面量完全相同(’…’),但只允许字母(A-Za-z)、数字(0-9)、方括号([])、点(.)、横线(-)、下划线(_),因此不能有空白符,不能有逗号等等。

    token不需要使用任何引号包围,因此,可使用:

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

    文本操作

    • 字符串连接:+
    th:text="'The name of the user is ' + ${user.name}"
    • 字面量替换:|The name is ${name}|

    字面量替换可以省略“+”操作符:

    <span th:text="|Welcome to our application, ${user.name}!|">
    等价于:
    <span th:text="'Welcome to our application, ' + ${user.name} + '!'">
    也可以结合其它类型的表达式使用:
    <span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">
    注意:只有变量表达式${…}才允许出现在|…|字面量替换中,其它的字面量’…’、布尔/数字token、条件表达式等等都不行
     

    算法操作

    • 二元操作符:+,-,*,/(div),%(mod)

    由Thymeleaf标准表达式引擎处理运算

    th:with="isEven=(${prodStat.count} % 2 == 0)"
    由OGNL引擎处理运算
    th:with="isEven=${prodStat.count % 2 == 0}"
     
    • 负号(一元操作符):-

    布尔操作

    • 二元操作符:and,or
    • 布尔取反(一元操作符):!,not

    比较及相等操作

    • 比较操作符:>,<,>=,<=(gt,lt,ge,le)
    th:if="${prodStat.count} &gt; 1"
    • 相等操作符:==,!=(eq,ne)
    th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')"

    条件操作符

    • if-then: (if)?(then)
    • if-then-else:(if)?(the):(else)
    <tr th:class="${row.even}? 'even' : 'odd'">
      ...
    </tr>
    条件表达式中的三个部分自身也是表达式,也可以是变量(${...}, *{...}), 消息(#{...}), URL (@{...}) 或字面量 ('...')
    条件表达式也可以使用括号来嵌套:
    <tr th:class="${row.even}? (${row.first}? 'first' : 'even') : 'odd'">
      ...
    </tr>
    else表达式也可以省略,当条件为false时,会返回null:
    <tr th:class="${row.even}? 'alt'">
      ...
    </tr>
    • default:(value)?:(defaultValue)

    这是没有then部分的特殊的条件表达式,又叫做Elvis操作,只有在第一个表达式返回null时,第二个表达式才会运算:

    <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>
    也可以包含嵌套的表达式:
    <p>
      Name: 
      <span th:text="*{firstName}?: (*{admin}? 'Admin' : #{default.username})">Sebastian</span>
    </p>

    综合案例

    'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))
     

    表达式工具对象

    • #dates 与java.util.Date对象的方法对应,格式化、日期组件抽取等等
    • #calendars 类似#dates,与java.util.Calendar对象对应
    • #numbers 格式化数字对象的工具方法
    • #strings 与java.lang.String对应的工具方法:contains、startsWith、prepending/appending等等
    • #objects 用于对象的工具方法
    • #bools 用于布尔运算的工具方法
    • #arrays 用于数组的工具方法
    • #lists 用于列表的工具方法
    • #sets 用于set的工具方法
    • #maps 用于map的工具方法
    • #aggregates 用于创建数组或集合的聚合的工具方法
    • #messages 用于在变量表达式内部获取外化消息的工具方法,与#{…}语法获取的方式相同
    • #ids 用于处理可能重复出现(例如,作为遍历的结果)的id属性的工具方法

     

    链接URL

    URL在web模板中是一级重要元素,使用@{…}表示

    URL的类型:

    • 绝对URL:http://www.thymeleaf.org
    • 相对URL:
      • 页面相对: user/login.html
      • 上下文相对:/itemdetails?id=3 (服务器上下文名称会被自动添加)
      • 服务器相对:~/billing/processInvoice(允许调用同一服务器上的另一个上下文中的URL)
      • 协议相对://code.jquery.com/jquery-2.0.3.min.js

     

    Thymeleaf在任何情况下都可以处理绝对URL,对于相对URL,则需要使用一个实现了IWebContext接口的上下文对象,这个对象包含了来自HTTP请求的信息,这些信息用于创建相对链接。

     

    <!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
    <a href="details.html" 
       th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
    
    <!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
    <a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
    
    <!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
    <a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
     

    预处理

    Thymeleaf提供预处理表达式的功能。

    它是在表壳式正常执行前执行的操作,允许修改最终将要被执行的表达式。

    预处理表达式跟正常的一样,但被两个下划线包围住,例如:__${expression}__

    假设有一个i18n消息文件Message_fr.properties,里面有一个条目包含了一个调用具体语言的静态方法的OGNL表达式:

    article.text=@myapp.translator.Translator@translateToFrench({0})
     
    Messages_es.properties中的等价条目:
    article.text=@myapp.translator.Translator@translateToSpanish({0})
     
     
    可以根据locale先创建用于运算表达式的标记片段,本例中,先通过预处理选择表达式,然后让Thymeleaf处理这个选择出来的表达式:
    <p th:text="${__#{article.text('textVar')}__}">Some text here...</p>
     
    对于locale为French的情况,上面的表达式经过预处理后,得出的等价物如下:
    <p th:text="${@myapp.translator.Translator@translateToFrench(textVar)}">Some text here...</p>
     

    设置属性值

    • th:attr任何属性值

    <form action="subscribe.html" th:attr="action=@{/subscribe}">
      <fieldset>
        <input type="text" name="email" />
        <input type="submit" value="Subscribe me!" th:attr="value=#{subscribe.submit}"/>
      </fieldset>
    </form>
    多个属性一起设置
    <img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
     
    • 设置指定属性

    <input type="submit" value="Subscribe me!" 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>
    所有的指定属性:
    | |th:abbr |th:accept |th:accept-charset | |th:accesskey |th:action |th:align | |th:alt |th:archive |th:audio | |th:autocomplete |th:axis |th:background | |th:bgcolor |th:border |th:cellpadding | |th:cellspacing |th:challenge |th:charset | |th:cite |th:class |th:classid | |th:codebase |th:codetype |th:cols | |th:colspan |th:compact |th:content | |th:contenteditable |th:contextmenu |th:data | |th:datetime |th:dir |th:draggable | |th:dropzone |th:enctype |th:for | |th:form |th:formaction |th:formenctype | |th:formmethod |th:formtarget |th:frame | |th:frameborder |th:headers |th:height | |th:high |th:href |th:hreflang | |th:hspace |th:http-equiv |th:icon | |th:id |th:keytype |th:kind | |th:label |th:lang |th:list | |th:longdesc |th:low |th:manifest | |th:marginheight |th:marginwidth |th:max | |th:maxlength |th:media |th:method | |th:min |th:name |th:optimum | |th:pattern |th:placeholder |th:poster | |th:preload |th:radiogroup |th:rel | |th:rev |th:rows |th:rowspan | |th:rules |th:sandbox |th:scheme | |th:scope |th:scrolling |th:size | |th:sizes |th:span |th:spellcheck | |th:src |th:srclang |th:standby | |th:start |th:step |th:style | |th:summary |th:tabindex |th:target | |th:title |th:type |th:usemap | |th:value |th:valuetype |th:vspace | |th:width |th:wrap |th:xmlbase | |th:xmllang |th:xmlspace | |
     
    • 追加
    <input type="button" value="Do it!" class="btn" th:attrappend="class=${' ' + cssStyle}" />
    <tr th:each="prod : ${prods}" class="row" th:classappend="${prodStat.odd}? 'odd'">
     
    • 修复的布尔属性
    <input type="checkbox" name="active" th:checked="${user.active}" />
    所有修复的布尔属性:
    -| |th:async |th:autofocus |th:autoplay | |th:checked |th:controls |th:declare | |th:default |th:defer |th:disabled | |th:formnovalidate|th:hidden |th:ismap | |th:loop |th:multiple |th:novalidate | |th:nowrap |th:open |th:pubdate | |th:readonly |th:required |th:reversed | |th:scoped |th:seamless |th:selected |
     
    • HTML5友好的属性及元素名
    <table>
        <tr data-th-each="user : ${users}">
            <td data-th-text="${user.login}">...</td>
            <td data-th-text="${user.name}">...</td>
        </tr>
    </table>
    data-{prefix}-{name}是编写HTML5自定义属性的标准语法,不需要开发者使用th:*这样的命名空间,Thymeleaf让这种语法自动对所有dialect都可用。
     
     

    遍历

    • 基础
    <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>
    可遍历的对象:实现java.util.Iterable、java.util.Map(遍历时取java.util.Map.Entry)、array、任何对象都被当作只有对象自身一个元素的列表
    • 状态
      • 当前遍历索引,从0开始,index属性
      • 当前遍历索引,从1开始,count属性
      • 总元素数量,size属性
      • 每一次遍历的iter变量,current属性
      • 当前遍历是even还是odd,even/odd布尔属性
      • 当前遍历是第一个,first布尔属性
      • 当前遍历是最后一个,last布尔属性
    <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>
     
    若不指定状态变量,Thymeleaf会默认生成一个名为“变量名Stat”的状态变量:
    <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>
     

    条件运算

    <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>
     
    <a href="comments.html"
       th:href="@{/product/comments(prodId=${prod.id})}" 
       th:if="${not #lists.isEmpty(prod.comments)}">view</a>
     
    th:if不只运算布尔条件,它对以下情况也运算为true:
    • 值不为null
      • 值为boolean且为true
      • 值为数字且非0
      • 值为字符且非0
      • 值是字符串且不是:“false”,“off”,“no”
      • 值不是boolean、数字、字符、字符串
    • 如果值为null,则th:if运算结果为false
     
    <a href="comments.html"
       th:href="@{/comments(prodId=${prod.id})}" 
       th:unless="${#lists.isEmpty(prod.comments)}">view</a>
    th:if的反面是th:unless
     
    <div th:switch="${user.role}">
      <p th:case="'admin'">User is an administrator</p>
      <p th:case="#{roles.manager}">User is a manager</p>
    </div>
     
    <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>
  • 相关阅读:
    VysorPro助手
    Play 2D games on Pixel running Android Nougat (N7.1.2) with Daydream View VR headset
    Play 2D games on Nexus 6P running Android N7.1.1 with Daydream View VR headset
    Native SBS for Android
    ADB和Fastboot最新版的谷歌官方下载链接
    How do I install Daydream on my phone?
    Daydream Controller手柄数据的解析
    蓝牙BLE传输性能及延迟分析
    VR(虚拟现实)开发资源汇总
    Android(Java)控制GPIO的方法及耗时分析
  • 原文地址:https://www.cnblogs.com/mark-chan/p/5491775.html
Copyright © 2011-2022 走看看