Thymeleaf

Thymeleaf是一个用于Web和独立环境的现代服务器端Java模板引擎,能够处理HTML、XML、JavaScript、CSS甚至纯文本。
Thymeleaf允许处理六种模板,有两种标记模板模式(HTML和XML)、三种文本模板模式(文本、JAVASCRIPT和CSS)和一种无操作模板模式(RAW)。

Thymeleaf和Vue的关系
不是一个层面的,vue是前端渲染,后端数据以json形式提供,前后端交互只有纯数据;thymeleaf相当于过去的jsp,当然比jsp先进不少,是后端渲染,后端直接推送的是整个html文档,缺点是服务器压力增大,渲染的东西比较多。
在前后端不分离的情况下,springboot推荐用html做页面,然后用thymeleaf做模板引擎,做数据渲染,但是这种方式还是要用js或者jquery手动去操作dom;前后端分离的情况下直接使用vue、react等

官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#introducing-thymeleaf


声明Thymeleaf的命名空间:

<html xmlns:th="http://www.thymeleaf.org">(官网文档)
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">(IDEA默认,推荐)
【分析】
官方给的声明方法,在旧版本的HTML5中无法识别th:*需要改成data-th-*,现在虽然可以识别,但是不会检查错误(如:th:text111data-th-text111),但第二种声明方法可以检查th:*的错误。


一、文本标签 th:text/th:utext

  1. th:text 进行文本替换,不会解析html
  2. th:utext 进行文本替换,会解析html
    (会出现警告:属性th:这里不允许utext)

二、属性操作

  1. 逻辑运算:+-*/%andor><>=<===!=!
    (运算符左右空格不影响)
  2. 字符串拼接:|name is ${name}|
    (||中空格有影响)
//a=1,b=2
<p th:text="${a} + ${b}"></p>
<p th:text="|${a} ${b}|"></p>
//等价于:
<p th:text="${a} + ' ' + ${b}"></p>

3
1 2
1 2

三、表达式

(1)变量表达式:${…}

最常用的方式,${a}${user.name}

不友好的地方:

<p style="color: red" th:text="${student.stuno}">1</p>

<p style="color: red" th:text="${student}?${student.stuno}:_">1</p>

如上若返回的student对象不存在,不会默认输出1,而是出现500报错。需要通过三目运算符判断,若想直接判断student.stuno的话需要在后端查找为空时构造一个无参的student对象。

(2)选择变量表达式:*{…}

一般用法和${…}相同,特殊用法th:object一起使用

//以下三者等价
<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>
  <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>

<div th:object="${session.user}">
  //当对象选择就绪时,所选对象也将作为#object表达式变量对美元表达式可用
  <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>

条件表达式也可以使用括号嵌套:

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

(3)消息表达式:#{…}

比较少用到,用于国际化message.properties属性读取

Welcome to our grocery store, {0}!

定义国际化处理转换处理类

@Configuration
public class LocaleResolverConfig {
    @Bean(name="localeResolver")
    public LocaleResolver localeResolverBean() {
        return new SessionLocaleResolver();
    }
}

定义国际化处理的controller

@Controller
public class ProductController {

    @Autowired
    private LocaleResolver localeResolver;
    private  ProductService productService = new ProductService();

    @RequestMapping("/messages")
    public String messages(Model model,HttpServletRequest request,HttpServletResponse response) {
        //设置访问用户信息到session
        request.getSession(true).setAttribute("user", new User("唐宋丶"));
        localeResolver.setLocale(request,response,Locale.CHINA);
        return "messages";
    }
}
<p th:utext="#{home.welcome(${session.user.name})}">Welcome to our grocery store, Sebastian!</p>

Welcome to our grocery store, 唐宋丶!

如果没有定义 message_en_US.properties 和 message_zh_CN.properties 会默认取message.properties中的信息
如果 Locale = Locale.CHINA 就取 message_zh_CN.properties
如果 Locale = Locale.US 就取 message_en_US.properties。

(4)链接URL表达式:@{…}

一般和th:hrefth:src进行结合使用,用于显示Web 应用中的URL链接。通过@{...}表达式Thymeleaf 可以帮助我们拼接上web应用访问的全路径(若配置文件配置端口访问项目名,则会自动补齐项目名),同时我们可以通过()进行参数的拼接

<img th:src="@{/img/favicon.ico}" alt="">
等同于:(图片在classpath:static/img/)
<img th:src="localhost:8080/img/favicon.ico" alt="">

<a th:href="@{/sys/test(id=${session.id},id2=${session.id2})}">test id</a>
<a th:href="@{/sys/test(id=1,id2=2)}">test id</a>
等同于
<a th:href="localhost:8080/sys/test?id=1&id2=2">test id</a>

(5)分段表达式:~{…}

片段表达式是一种表示标记片段并在模板之间移动它们的简单方法。这允许我们复制它们,将它们作为参数传递给其他模板,等等。
最常见的用法是使用th:insertth:replace来插入片段(关于这些的更多信息将在后面的小节中介绍)


四、if/unless/switch/each

  • th:if: 当条件为true则显示。
  • th:unless: 当条件为false则显示。
  • th:switch: 与th:case完成条件表达式操作。
//chose=1
<div th:switch="${chose}">
    <p th:case="1">1</p>
    <p th:case="2">2</p>
    ---
    <p th:if="${chose} > 0">if</p>
</div>

1
---
if
  • thLeach: 遍历集合
    我们可以通过便利的 变量名+Stat 来获取索引 是否是第一个或最后一个等。便利的变量名+Stat称作状态变量,其属性有:

    • index:当前迭代对象的迭代索引,从0开始,这是索引属性;
    • count:当前迭代对象的迭代索引,从1开始,这个是统计属性;
    • size:迭代变量元素的总量,这是被迭代对象的大小属性;
    • current:当前迭代变量;
    • even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算);
    • first:布尔值,当前循环是否是第一个;
    • last:布尔值,当前循环是否是最后一个
<style type="text/css">
    .even {border: blue solid 1px}
    .odd {border: red solid 1px}
</style>

<div th:each="user : ${userList}" th:class="${userStat.odd} ? 'odd' : 'even'">
    <p th:text="${user.name}">姓名</p>
    <p th:text="${user.age}">年龄</p>
</div>

姓名1 
年龄1

姓名2 
年龄2

五、href/src/class/attr/attrappend/value/action/id/style/with

  • th:href:用于声明在<a>标签上的href属性的链接,该语法会和@{..}表达式一起使用,详见上文。
  • th:src:同上。
  • th:class:用于声明在标签上class属性信息。针对不同值更改其css,详解上文thLeach
  • th:attr:在标记中设置(或修改)属性值。但官方文档标明,更希望通过th:valueth:action去改变属性。
<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>
//等同于
<form action="subscribe.html" th:action="@{/subscribe}">
  <fieldset>
    <input type="text" name="email" />
    <input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>
  </fieldset>
</form>

<img src="../../images/gtvglogo.png"  th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
//等同于
<img src="../../images/gtvglogo.png"  th:src="@{/images/gtvglogo.png}" th:title="#{logo}" th:alt="#{logo}" />
  • th:attrappend:追加属性,您可能想要将一个CSS类的名称存储到一个上下文变量中的一个按钮上(不是设置,而是添加),因为要使用的特定CSS类取决于用户之前所做的事情
<input type="button" value="Do it!" class="btn" th:attrappend="class=${' ' + cssStyle}" />
等同于,
<input type="button" value="Do it!" class="btn warning" />

若只用于追加css相关,也可用th:classappend
<tr th:each="prod : ${prods}" class="row" th:classappend="${prodStat.odd}? 'odd'">
  • th:value:用于修改属性值,如上。
  • th:action:用于form表单,如上。
  • th:id:用于声明HTML的id属性:<p th:id="${id}"></p>
  • th:style:用于声明htm中的标签 css的样式信息。
<p th:style="'display:' + @{(${isShow} ? 'none' : 'block')} + ''"></p>

<p style="display:none"></p>
  • th:with:用于thymeleaf 模版页面中局部变量定义的使用。
<div th:with="isEven=(${prodStat.count} % 2 == 0)">

<div th:with="firstPer=${persons[0]},secondPer=${persons[1]}">
  <p>
    The name of the first person is <span th:text="${firstPer.name}">Julius Caesar</span>.
  </p>
  <p>
    But the name of the second person is 
    <span th:text="${secondPer.name}">Marcus Antonius</span>.
  </p>
</div>

//处理日期
date.format=dd ''de'' MMMM'','' yyyy
<p th:with="df=#{date.format}">
  Today is: <span th:text="${#calendars.format(today,df)}">13 February 2011</span>
</p>

六、Elvis/三目运算符

  • Elvis运算可以理解成简单的判断是否为null的三元运算的简写,如果值为null则显示默认值,如果不为null则显示原有的值。
<span th:text="${age2}?: '年龄为nll'"></span>

//若为null则什么也不做
<span th:text="${name} ?: _">no user authenticated</span>
  • 三目运算符,可以增加条件表达式

    • gt:great than(大于)
    • ge:great equal(大于等于)
    • eq:equal(等于)
    • lt:less than(小于)
    • le:less equal(小于等于)
    • ne:not equal(不等于)
//flag=(int)1
//(推荐)方法一自动把flag转成字符串再比较,相等
<p th:text = "${flag} eq '1' ? '1' : 'no 1'">1</p>
//方法二直接(int)1与(String)1比较,不相等
<p th:text = "${flag eq '1' ? '1' : 'no 1'}">no 1</p>

七、内联

内联相当于引用变量,[[...]]对应于th:text[(...)]对应于th:utext
禁用:<p th:inline="none">
开启:

//整个页面可以 th:index="body"
<div th:inline="text">
   <p>Hello, [[${user.name}]]!</p>
   //等同于
   <p th:text="|Hello, ${user.name}|"></p>
</div>

//JS
<script th:inline="javascript">
    var username = [[${user.name}]];
</script>

//CSS
//classname = 'main'、align = 'center'
<style th:inline="css">
    .[[${classname}]] {
      text-align: [[${align}]];
    }
</style>

八、模板布局

  • 定义引用片段代码,一般通过th:fragment来定义引用片段,通过th:insert~{...}片段引用表达式,进行引入片段,如插入footer.html页面
  • 通过id属性来声明片段,只需将th:fragment替换为id
//通过th:fragment来定义引用片段,在其他页面进行引用
footer.html
<body>
    <div th:fragment="copy">
        &copy; 2011 The Good Thymes Virtual Grocery
    </div>
    <div id="copy-section" >
        &copy; 2011 The Good Thymes Virtual Grocery
    </div>
</body>

index.html
<body>
    //两种方式都可
    <div th:insert="footer :: copy"></div>
    <div th:insert="~{footer :: copy}"></div>
    <div th:insert="~{footer :: #copy-section}"></div>
</body>
//带参引用
fotter.html
<body>
<div th:fragment="frag (onevar,twovar)">
    <p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>
</body>

index.html
<body>
    <div th:insert="footer :: frag('a','b')"></div>
</body>

结果
<div>
<div>
    <p>a - b</p>
</div>
</div>

【区别】:

  • th:insert 将使用th:insert标签引用片段的标签内容都显示出来
  • th:replace 插入引用片段的标签内容,原来的标签被替换了
  • th:include th:insert标签,只插入引用片段的内容**。
  • th:remove: 删除模版片段,一般用于删除模拟数据,常用th:remove="all"

    • all:删除包含标记及其所有子标记。
    • body:不要删除包含标记,但删除其所有子标记。
    • tag:删除包含标记,但不删除其子项。
    • all-but-first:删除除第一个之外的所有包含标记的子项。
    • none: 没做什么。此值对于动态评估很有用。

dates

/*
 * 使用标准地区格式格式化日期
 * 也可用于数组、列表或集合
 */
${#dates.format(date)}
2020年5月6日 下午10时13分39秒
${#dates.arrayFormat(datesArray)}
${#dates.listFormat(datesList)}
${#dates.setFormat(datesSet)}

/*
 * 格式日期采用ISO8601格式
 * 也可用于数组、列表或集合
 */
${#dates.formatISO(date)}
2020-05-06T22:21:05.809+08:00 
${#dates.arrayFormatISO(datesArray)}
${#dates.listFormatISO(datesList)}
${#dates.setFormatISO(datesSet)}

/*
 * 使用指定的模式格式化日期
 * 也可用于数组、列表或集合
 */
${#dates.format(date, 'dd/MMM/yyyy HH:mm')}
06/五月/2020 22:21
${#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.
当天是这周的第几天,周日开始算,5
${#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.

/*
 * 从它的组件中创建date (java.util.Date)对象
 * year,month,day,hour,minute...为自己输入
 */
${#dates.create(year,month,day)}
Wed May 20 00:00:00 CST 2020 
${#dates.create(year,month,day,hour,minute)}
${#dates.create(year,month,day,hour,minute,second)}
${#dates.create(year,month,day,hour,minute,second,millisecond)}

/*
 * 为当前日期和时间创建一个date (java.util.Date)对象
 */
${#dates.createNow()}
Thu May 07 10:51:32 CST 2020
${#dates.createNowForTimeZone()}

/*
 * 为当前日期(时间设置为00:00)创建一个日期(java.util.Date)对象
 */
${#dates.createToday()}
Thu May 07 00:00:00 CST 2020
${#dates.createTodayForTimeZone()}

numbers

/*
 * ==========================
 * 格式化整型数字
 * ==========================
 */

/* 
 * 设置最小整数位数。
 * 也可用于数组、列表或集合
 */
${#numbers.formatInteger(num,3)}
指定位数,0补齐,num大于指定位数则返回num
(12,3)->012、(1234,3)->1234
${#numbers.arrayFormatInteger(numArray,3)}
[001, 012, 123]
${#numbers.listFormatInteger(numList,3)}
[001, 012, 123]
${#numbers.setFormatInteger(numSet,3)}


/* 
 * 设置最小整数位数和千位分隔符:
 * 'POINT'='.', 'COMMA'=',', 'WHITESPACE'=' ', 'NONE' or 'DEFAULT' (by locale).
 * 也可用于数组、列表或集合
 */
${#numbers.formatInteger(num,3,'POINT')}

(1000,3,POINT)->1.000、(1000,6,POINT)->001.000
${#numbers.arrayFormatInteger(numArray,3,'POINT')}
${#numbers.listFormatInteger(numList,3,'POINT')}
${#numbers.setFormatInteger(numSet,3,'POINT')}


/*
 * ==========================
 * 格式化小数
 * ==========================
 */

/*
 * 设置最小整数位数和(精确的)小数位数。
 * 也可用于数组、列表或集合
 */
${#numbers.formatDecimal(num,3,2)}
(10.123,3,2)->010.12
${#numbers.arrayFormatDecimal(numArray,3,2)}
${#numbers.listFormatDecimal(numList,3,2)}
${#numbers.setFormatDecimal(numSet,3,2)}

/*
 * 设置最小整数位数和(精确的)小数位数,以及小数分隔符。
 * 也可用于数组、列表或集合
 */
${#numbers.formatDecimal(num,3,2,'COMMA')}
(1000.123,5,2,COMMA)->01000,12
${#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')}
(1000.123,5,POINT,2,COMMA)->01.000,12
${#numbers.arrayFormatDecimal(numArray,3,'POINT',2,'COMMA')}
${#numbers.listFormatDecimal(numList,3,'POINT',2,'COMMA')}
${#numbers.setFormatDecimal(numSet,3,'POINT',2,'COMMA')}


/* 
 * =====================
 * 格式化货币
 * =====================
 */

${#numbers.formatCurrency(num)}
(1000)->¥1,000.00
${#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)}
(0.2,2,4)->20.0000%
${#numbers.arrayFormatPercent(numArray, 3, 2)}
${#numbers.listFormatPercent(numList, 3, 2)}
${#numbers.setFormatPercent(numSet, 3, 2)}


/*
 * ===============
 * 工具方法
 * ===============
 */

/*
 * 创建一个整数序列(数组)
 * 从x到y(包括x、y),每次累加z
 */
${#numbers.sequence(from,to)}
${#numbers.sequence(from,to,step)}
div th:each="num : ${#numbers.sequence(0,4,2)}" >
         <p th:text="${num}"></p>
</div>

<div><p>0</p></div>
<div><p>2</p></div>
<div><p>4</p></div>

Strings

/*
 * 字符串转换
 */
${#strings.toString(obj)}                           // also array*, list* and set*
123、[1, 12, 123]
/*
 * 检查字符串是否为空(或null)。在检查之前执行trim()操作
 * 也可用于数组、列表或集合
 */
${#strings.isEmpty(name)}
判断是否为空,返回true/false
${#strings.arrayIsEmpty(nameArr)}
[fales, true]
${#strings.listIsEmpty(nameList)}
${#strings.setIsEmpty(nameSet)}

/*
 * 对一个字符串执行'isEmpty()'检查,如果为false则返回该字符串,如果为true则默认返回另一个指定的字符串。
 * 也可用于数组、列表或集合
 */
${#strings.defaultString(text,default)}
非空返回前者text,空返回后者default
text=null,default='该值为null'->该值为null
${#strings.arrayDefaultString(textArr,default)}
${#strings.listDefaultString(textList,default)}
${#strings.setDefaultString(textSet,default)}

/*
 * 检查一个片段是否包含在一个字符串中
 * 也可用于数组、列表或集合
 */
${#strings.contains(name,'ze')}                     // also array*, list* and set*
('zzze','ze')->true
${#strings.containsIgnoreCase(name,'ze')}           // also array*, list* and set*
不区分大小写('ZZZE','ze')->true
/*
 * 检查字符串是否以片段开始或结束
 * 也可用于数组、列表或集合
 */
${#strings.startsWith(name,'Don')}                  // also array*, list* and set*
${#strings.endsWith(name,endingFragment)}           // also array*, list* and set*

/*
 * 子串相关操作
 * 也可用于数组、列表或集合
 */
${#strings.indexOf(name,frag)}                      // also array*, list* and set*
返回下标位置,从0开始
${#strings.substring(name,3,5)}                     // also array*, list* and set*
返回[3,5)子串,即下标为3、4
${#strings.substringAfter(name,prefix)}             // also array*, list* and set*
第4个之后(不包括第4),('12345',4)->'5'
${#strings.substringBefore(name,suffix)}            // also array*, list* and set*
第4个之前(不包括第4),('12345',4)->'123'
${#strings.replace(name,'las','ler')}               // also array*, list* and set*
若存在则后者ler替换 前者las
/*
 * 附加和预加
 * 也可用于数组、列表或集合
 */
${#strings.prepend(str,prefix)}                     // also array*, list* and set*
prefix加在str之前
${#strings.append(str,suffix)}                      // also array*, list* and set*
suffix加在str之后

/*
 * 大小写转换
 * 也可用于数组、列表或集合
 */
${#strings.toUpperCase(name)}                       // also array*, list* and set*
${#strings.toLowerCase(name)}                       // also array*, list* and set*

/*
 * 分割和连接
 */
${#strings.arrayJoin(namesArray,',')}
${#strings.listJoin(namesList,',')}
${#strings.setJoin(namesSet,',')}
${#strings.arraySplit(namesStr,',')}                // returns String[]
${#strings.listSplit(namesStr,',')}                 // returns List<String>
${#strings.setSplit(namesStr,',')}                  // returns Set<String>

/*
 * 修剪
 * 也可用于数组、列表或集合
 */
${#strings.trim(str)}                               // also array*, list* and set*
去首位空格
/*
 * 计算长度
 * 也可用于数组、列表或集合
 */
${#strings.length(str)}                             // also array*, list* and set*

/*
 * 缩写文本,使其最大大小为n。如果文本更大,它将被剪切并以“…”结束。也可用于数组、列表或集合
 */
${#strings.abbreviate(str,10)}                      // also array*, list* and set*
省略号...占三个位置
('0123456789',7)->'0123...'
/*
 * 将第一个字符转换为大写(反之亦然)
 */
${#strings.capitalize(str)}                         // also array*, list* and set*
${#strings.unCapitalize(str)}                       // also array*, list* and set*

/*
 * 将每个单词的第一个字符转换为大写
 */
${#strings.capitalizeWords(str)}                    // also array*, list* and set*
${#strings.capitalizeWords(str,delimiters)}         // also array*, list* and set*

/*
 * 转义字符串
 */
${#strings.escapeXml(str)}                          // also array*, list* and set*
${#strings.escapeJava(str)}                         // also array*, list* and set*
${#strings.escapeJavaScript(str)}                   // also array*, list* and set*
${#strings.unescapeJava(str)}                       // also array*, list* and set*
${#strings.unescapeJavaScript(str)}                 // also array*, list* and set*

/*
 * 空安全的比较和连接
 */
${#strings.equals(first, second)}
比较两字符串是否相等
${#strings.equalsIgnoreCase(first, second)}
比较两字符串是否相等,忽略大小写
${#strings.concat(values...)}
拼接数组
${#strings.concatReplaceNulls(nullValue, values...)}

/*
 * Random
 */
${#strings.randomAlphanumeric(count)}
随机生成count位数的字符串(大写字符+数字)

Objects

/*
 * 如果obj不为空,则返回obj,否则返回默认值
 * 也可用于数组、列表或集合
 */
${#objects.nullSafe(obj,default)}
非空返回obj,空返回default
${#objects.arrayNullSafe(objArray,default)}
${#objects.listNullSafe(objList,default)}
${#objects.setNullSafe(objSet,default)}

Booleans

/*
 * 判断ture
 * 也可用于数组、列表或集合
 */
${#bools.isTrue(obj)}
判断obj是否为true
true、非0、'on'->true
false、0、'off'->false
${#bools.arrayIsTrue(objArray)}
${#bools.listIsTrue(objList)}
${#bools.setIsTrue(objSet)}

/*
 * 判断false
 * 也可用于数组、列表或集合
 */
${#bools.isFalse(cond)}
${#bools.arrayIsFalse(condArray)}
${#bools.listIsFalse(condList)}
${#bools.setIsFalse(condSet)}

/*
 * 评估、应用And操作
 * 接收数组、列表或集合作为参数
 */
${#bools.arrayAnd(condArray)}
[T、T、F]->F
${#bools.listAnd(condList)}
${#bools.setAnd(condSet)}

/*
 * 评估和应用OR操作符
 * 接收数组、列表或集合作为参数
 */
${#bools.arrayOr(condArray)}
[T、T、F]->T
${#bools.listOr(condList)}
${#bools.setOr(condSet)}

Arrays

/*
 * 转换为数组,尝试推断数组组件类。注意,如果结果数组是空的,或者目标对象的元素不都是同一个类,这个方法将返回object[]。
 */
${#arrays.toArray(object)}

/*
 * 转换为指定组件类的数组。
 */
${#arrays.toStringArray(object)}
对象类型打印(java.lang.String;@3cca655d)
${#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)}
判断element元素是否在array数组中
${#arrays.containsAll(array, elements)}
判断elements数据中的所有元素是否在array数组中

Lists

/*
 * 转换为列表
 */
${#lists.toList(object)}

/*
 * 返回长度
 */
${#lists.size(list)}

/*
 * 判断是否为空
 */
${#lists.isEmpty(list)}

/*
 * 检查元素是否包含在列表中
 */
${#lists.contains(list, element)}
${#lists.containsAll(list, elements)}

/*
 * 对给定列表的副本进行排序。列表的成员必须实现
 * comparable或必须定义一个比较器。
 */
${#lists.sort(list)}
${#lists.sort(list, comparator)}

Sets

/*
 * 转换为set
 */
${#sets.toSet(object)}

/*
 * 计算长度
 */
${#sets.size(set)}

/*
 * 判断是否为空
 */
${#sets.isEmpty(set)}

/*
 * 检查集合中是否包含元素
 */
${#sets.contains(set, element)}
${#sets.containsAll(set, elements)}

Maps

${#maps.size(map)}
${#maps.isEmpty(map)}
${#maps.containsKey(map, key)}
${#maps.containsAllKeys(map, keys)}
${#maps.containsValue(map, value)}
${#maps.containsAllValues(map, value)}

Aggregates

/*
 * 计算总和。如果数组或集合为空,则返回null
 */
${#aggregates.sum(array)}
Integer[] array = {1,2,3,4};
${#aggregates.sum(collection)}
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
/*
 * 计算的平均水平。如果数组或集合为空,则返回null
 */
${#aggregates.avg(array)}
${#aggregates.avg(collection)}

IDs

/*
 * Normally used in th:id attributes, for appending a counter to the id attribute value
 * so that it remains unique even when involved in an iteration process.
 */
${#ids.seq('someId')}

/*
 * 通常在th:中用于<label> tags中的属性,以便这些标签可以引用id
 * 通过方法生成如:#ids.seq(…)函数。
 * 
 * 取决于<label>是在#ids.seq(…)函数,之前还是之后。
 * “next”(标签在“seq”之前)或“prev”函数(标签"seq"在后面),函数应该被调用。
 */
${#ids.next('someId')}
${#ids.prev('someId')}

属性优先级

OrderFeatureAttributes
1Fragment inclusionth:insert
th:replace
2Fragment iterationth:each
3Conditional evaluationth:if
th:unless
th:switch
th:case
4Local variable definitionth:object
th:with
5General attribute modificationth:attr
th:attrprepend
th:attrappend
6Specific attribute modificationth:value
th:href
th:src
...
7Text (tag body modification)th:text
th:utext
8Fragment specificationth:fragment
9Fragment removalth:remove

日志相关

//TRACE DEBUG INFO
log4j.logger.org.thymeleaf=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.CONFIG=TRACE
//将在初始化期间输出库的详细配置。
log4j.logger.org.thymeleaf.TemplateEngine.TIMER=TRACE
将输出关于处理每个模板所需时间的信息(对于基准测试非常有用!)
log4j.logger.org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE=TRACE
是输出有关缓存的特定信息的一组日志记录器的前缀。
Last modification:May 30th, 2020 at 04:17 pm
喵ฅฅ