Loading... ## 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:text111`、`data-th-text111`),但第二种声明方法可以检查 `th:*`的错误。 --- ### 一、文本标签 th:text/th:utext 1. `th:text` 进行文本替换,不会解析html 2. `th:utext` 进行文本替换,会解析html (会出现警告:**属性th:这里不允许utext**) --- ### 二、属性操作 1. 逻辑运算:`+`、`-`、`*`、`/`、`%`、`and`、`or`、`>`、`<`、`>=`、`<=`、`==`、`!=`、`!` (运算符左右空格不影响) 2. 字符串拼接:`|name is ${name}|` (`||`中空格有影响) ```HTML //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}` **`不友好的地方:`** ```Java <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`一起使用 ```HTML //以下三者等价 <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> ``` 条件表达式也可以使用括号嵌套: ```HTML <tr th:class="${row.even}? (${row.first}? 'first' : 'even') : 'odd'"> ... </tr> ``` #### (3)消息表达式:`#{…}` 比较少用到,用于国际化message.properties属性读取 ```properties Welcome to our grocery store, {0}! ``` 定义国际化处理转换处理类 ```Java @Configuration public class LocaleResolverConfig { @Bean(name="localeResolver") public LocaleResolver localeResolverBean() { return new SessionLocaleResolver(); } } ``` 定义国际化处理的controller ```Java @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"; } } ``` ```HTML <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:href`、`th:src`进行结合使用,用于显示Web 应用中的URL链接。通过@{...}表达式Thymeleaf 可以帮助我们拼接上web应用访问的全路径(若配置文件配置端口访问项目名,则会自动补齐项目名),同时我们可以通过()进行参数的拼接 ```HTML <img th:src="@{/img/favicon.ico}" alt=""style=""> 等同于:(图片在classpath:static/img/) <img th:src="localhost:8080/img/favicon.ico" alt=""style=""> <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:insert`或 `th:replace`来插入片段(关于这些的更多信息将在后面的小节中介绍) --- ### 四、if/unless/switch/each * `th:if`: 当条件为 `true`则显示。 * `th:unless`: 当条件为 `false`则显示。 * `th:switch`: 与 `th:case`完成条件表达式操作。 ```HTML //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`:布尔值,当前循环是否是最后一个 ```HTML <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:value`、`th:action`去改变属性。 ```HTML <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}" style=""> ``` * `th:attrappend`:追加属性,您可能想要将一个CSS类的名称存储到一个上下文变量中的一个按钮上(不是设置,而是添加),因为要使用的特定CSS类取决于用户之前所做的事情 ```HTML <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的样式信息。 ```HTML <p th:style="'display:' + @{(${isShow} ? 'none' : 'block')} + ''"></p> <p style="display:none"></p> ``` * `th:with`:用于thymeleaf 模版页面中局部变量定义的使用。 ```HTML <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则显示原有的值。 ```HTML <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(不等于) ```HTML //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">` 开启: ```HTML //整个页面可以 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` ```HTML //通过th:fragment来定义引用片段,在其他页面进行引用 footer.html <body> <div th:fragment="copy"> © 2011 The Good Thymes Virtual Grocery </div> <div id="copy-section" > © 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> ``` ```HTML //带参引用 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 ```Java /* * 使用标准地区格式格式化日期 * 也可用于数组、列表或集合 */ ${#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 ```Java /* * ========================== * 格式化整型数字 * ========================== */ /* * 设置最小整数位数。 * 也可用于数组、列表或集合 */ ${#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)} ``` ```HTML 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 ```Java /* * 字符串转换 */ ${#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 ```Java /* * 如果obj不为空,则返回obj,否则返回默认值 * 也可用于数组、列表或集合 */ ${#objects.nullSafe(obj,default)} 非空返回obj,空返回default ${#objects.arrayNullSafe(objArray,default)} ${#objects.listNullSafe(objList,default)} ${#objects.setNullSafe(objSet,default)} ``` --- ### Booleans ```Java /* * 判断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 ```Java /* * 转换为数组,尝试推断数组组件类。注意,如果结果数组是空的,或者目标对象的元素不都是同一个类,这个方法将返回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 ```Java /* * 转换为列表 */ ${#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 ```Java /* * 转换为set */ ${#sets.toSet(object)} /* * 计算长度 */ ${#sets.size(set)} /* * 判断是否为空 */ ${#sets.isEmpty(set)} /* * 检查集合中是否包含元素 */ ${#sets.contains(set, element)} ${#sets.containsAll(set, elements)} ``` --- ### Maps ```Java ${#maps.size(map)} ${#maps.isEmpty(map)} ${#maps.containsKey(map, key)} ${#maps.containsAllKeys(map, keys)} ${#maps.containsValue(map, value)} ${#maps.containsAllValues(map, value)} ``` --- ### Aggregates ```Java /* * 计算总和。如果数组或集合为空,则返回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 ```Java /* * 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')} ``` --- ### 属性优先级 | Order | Feature | Attributes | | ----- | ------------------------------- | ------------------------------------------ | | 1 | Fragment inclusion | th:insert<br>th:replace | | 2 | Fragment iteration | th:each | | 3 | Conditional evaluation | th:if<br>th:unless<br>th:switch<br>th:case | | 4 | Local variable definition | th:object<br>th:with | | 5 | General attribute modification | th:attr<br>th:attrprepend<br>th:attrappend | | 6 | Specific attribute modification | th:value<br>th:href<br>th:src<br>... | | 7 | Text (tag body modification) | th:text<br>th:utext | | 8 | Fragment specification | th:fragment | | 9 | Fragment removal | th:remove | --- ### 日志相关 ```properties //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:August 12, 2022 © Allow specification reprint Like 0 喵ฅฅ