前端渲染模板(一):Thymeleaf

一、使用

  本篇文章将以SpringBoot为框架来介绍Thymeleaf的用法。

  1 资源文件的约定目录结构 

Maven的资源文件目录:/src/java/resources
spring-boot项目静态文件目录:/src/java/resources/static
spring-boot项目模板文件目录:/src/java/resources/templates
spring-boot静态首页的支持,即index.html放在以下目录结构会直接映射到应用的根目录下:

classpath:/META-INF/resources/index.html
classpath:/resources/index.html
classpath:/static/index.html
calsspath:/public/index.html

  因此,SpringBoot默认的静态资源文件应该放在resources/tatic下,而静态页面应该放在resources/templates文件夹下,这两个文件不会自动创建,需要手动创建,如下图所示:

                                                                                                                              

  2 Maven依赖:

1         <!-- thymeleaf 前端渲染模板依赖 -->
2         <dependency>
3             <groupId>org.springframework.boot</groupId>
4             <artifactId>spring-boot-starter-thymeleaf</artifactId>
5             <version>2.0.0.RELEASE</version>
6         </dependency>

  3 html页面中(<html>标签处):

1 <html xmlns="http://www.w3.org/1999/xhtml"
2       xmlns:th="http://www.thymeleaf.org"
3       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">

  4 application.properties配置(application.yml则根据格式相应变化即可):

 1 # THYMELEAF (ThymeleafAutoConfiguration)  
 2 #开启模板缓存(默认值:true)  
 3 spring.thymeleaf.cache=true   
 4 #Check that the template exists before rendering it.  
 5 spring.thymeleaf.check-template=true  
 6 #检查模板位置是否正确(默认值:true)  
 7 spring.thymeleaf.check-template-location=true  
 8 #Content-Type的值(默认值:text/html)  
 9 spring.thymeleaf.content-type=text/html  
10 #开启MVC Thymeleaf视图解析(默认值:true)  
11 spring.thymeleaf.enabled=true  
12 #模板编码  
13 spring.thymeleaf.encoding=UTF-8  
14 #要被排除在解析之外的视图名称列表,用逗号分隔  
15 spring.thymeleaf.excluded-view-names=  
16 #要运用于模板之上的模板模式。另见StandardTemplate-ModeHandlers(默认值:HTML5)  
17 spring.thymeleaf.mode=HTML5  
18 #在构建URL时添加到视图名称前的前缀(默认值:classpath:/templates/)  
19 spring.thymeleaf.prefix=classpath:/templates/  
20 #在构建URL时添加到视图名称后的后缀(默认值:.html)  
21 spring.thymeleaf.suffix=.html  
22 #Thymeleaf模板解析器在解析器链中的顺序。默认情况下,它排第一位。顺序从1开始,只有在定义了额外的TemplateResolver Bean时才需要设置这个属性。  
23 spring.thymeleaf.template-resolver-order=  
24 #可解析的视图名称列表,用逗号分隔  
25 spring.thymeleaf.view-names=  

  配置好以上的代码,此时在html模板文件中动态的属性使用th:命名空间修饰,就可以使用Thymeleaf了。

二、语法

  1 引用静态资源文件:

    比如CSS和JS文件,语法格式为“@{}”,如@{/js/blog/blog.js}会引入/static目录下的/js/blog/blog.js文件。

  2 访问spring-mvc中model的属性:

    语法格式为“${}”,如${user.id}可以获取model里的user对象的id属性,类似JSTL。

  3 循环:

    在html的标签中,加入th:each=“value:${list}”形式的属性,如<span th:each=”user:${users}”></span>可以迭代users的数据

  4 判断:    

在html标签中,加入th:if=”表达式”可以根据条件显示html元素

1 <span th:if="${not #lists.isEmpty(blog.publishTime)}"> 
2   <span id="publishtime" th:text="${#dates.format(blog.publishTime, 'yyyy-MM-dd HH:mm:ss')}"></span> 
3 </span> 

以上代码表示若blog.publishTime时间不为空,则显示时间。

5 时间格式化:

1 ${#dates.format(blog.publishTime,'yyyy-MM-dd HH:mm:ss')} //表示将时间格式化为”yyyy-MM-dd HH:mm:ss”格式化写法与Java格式化Date的写法是一致的。 

  6 字符串拼接:

    有两种形式 ,比如拼接这样一个URL:/blog/delete/{blogId} 

第一种:th:href="'/blog/delete/' + ${blog.id }"
第二种:th:href="${'/blog/delete/' + blog.id }"

7 为CSS样式的某些路径使用thyemleaf表达式:

1 <div th:style="'background:url(' + @{/<path-to-image>} + ');'"></div>

   8 使用th:utext="@{}" 可以让变量里面的html标签被解析

三、表达式

  1 简单表达式 (simple expressions)

1   ${...} 变量表达式
2 
3   *{...} 选择变量表达式
4 
5   #{...} 消息表达式
6 
7   @{...} 链接url表达式

  2 字面量

1   'one text','another one!',... 文本
2 
3   0,34,3.0,12.3,... 数值
4 
5   true false 布尔类型
6 
7   null 空
8 
9   one,sometext,main 文本字符

  3 文本操作

1   + 字符串连接
2 
3   |The name is ${name}| 字符串连接

  4 算术运算

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

  5 布尔操作

1   and,or 二元操作符
2 
3   !,not 非(一元操作符)

  6 关系操作符

1   > , < , >= , <= (gt , lt , ge , le)
2 
3   == , != (eq, ne)

  7 条件判断

1 (if) ? (then) if-then
2 
3 (if) ? (then) : (else) if-then-else
4 
5 <tr th:class="${row.even}? 'even' : 'odd'">
6 ...
7 </tr>

条件表达式中的三个部分自身也可以是表达式,也可以是变量(${...}, *{...}), 消息(#{...}), URL (@{...}) 或字面量 ('...')
条件表达式也可以使用括号来嵌套:

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

  else表达式也可以省略,当条件为false时,会返回null:

1 <tr th:class="${row.even}? 'alt'">
2 ...
3 </tr>
4 (value) ?: (defaultvalue) Default

  只有在第一个表达式返回null时,第二个表达式才会运算

  8 表达式工具对象

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

  9 链接URL

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

URL的类型:

  绝对URL:

http://www.thymeleaf.org

  相对URL:

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

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

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

  10 预处理
  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>

四、 设置属性值

  1 th:attr 任何属性值

1 <form action="subscribe.html" th:attr="action=@{/subscribe}">
2   <fieldset>
3     <input type="text" name="email" />
4     <input type="submit" value="Subscribe me!" th:attr="value=#{subscribe.submit}"/>
5   </fieldset>
6 </form>

  多个属性一起设置,用逗号隔开

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

  2 设置指定属性

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 ...
1 <input type="submit" value="Subscribe me!" th:value="#{subscribe.submit}"/>
2 <form action="subscribe.html" th:action="@{/subscribe}">
3 <li><a href="product/list.html" th:href="@{/product/list}">Product List</a></li>

  设置多个属性在同一时间 有两个特殊的属性可以这样设置: th:alt-title 和 th:lang-xmllang

th:alt-title 设置 alt 和 title
th:lang-xmllang 设置 lang 和 xml:lang

1 <img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
2 
3 <img src="../../images/gtvglogo.png"th:src="@{/images/gtvglogo.png}" th:title="#{logo}" th:alt="#{logo}" />
4 
5 <img src="../../images/gtvglogo.png"th:src="@{/images/gtvglogo.png}" th:alt-title="#{logo}" />

  前置和后置添加属性值 th:attrappend 和 th:attrprepend

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

  编译后:

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

  还有两个特定的添加属性 th:classappend 和 th:styleappend

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

  3 修复的布尔属性

<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友好的属性及元素名

1 <table>
2 <tr data-th-each="user : ${users}">
3 <td data-th-text="${user.login}">...</td>
4 <td data-th-text="${user.name}">...</td>
5 </tr>
6 </table>

  注:data-{prefix}-{name}是编写HTML5自定义属性的标准语法,不需要开发者使用th:*这样的命名空间,Thymeleaf让这种语法自动对所有dialect都可用。

五、遍历

  1 基础

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

  可遍历的对象:实现java.util.Iterable、java.util.Map(遍历时取java.util.Map.Entry)、array、任何对象都被当作只有对象自身一个元素的列表

  2 状态

当前遍历索引,从0开始,index属性
当前遍历索引,从1开始,count属性
总元素数量,size属性
每一次遍历的iter变量,current属性
当前遍历是even还是odd,even/odd布尔属性
当前遍历是第一个,first布尔属性
当前遍历是最后一个,last布尔属性

1 <tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
2   <td th:text="${prod.name}">Onions</td>
3   <td th:text="${prod.price}">2.41</td>
4   <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
5 </tr>

若不指定状态变量,Thymeleaf会默认生成一个名为“变量名Stat”的状态变量:

1 <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
2   <td th:text="${prod.name}">Onions</td>
3   <td th:text="${prod.price}">2.41</td>
4   <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
5 </tr>

六、条件运算

1 <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
2   <td th:text="${prod.name}">Onions</td>
3   <td th:text="${prod.price}">2.41</td>
4   <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
5   <td>
6     <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
7     <a href="comments.html" th:href="@{/product/comments(prodId=${prod.id})}" th:if="${not #lists.isEmpty(prod.comments)}">view</a>
8   </td>
9 </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

  th:if的反面是th:unless

 1 <a href="comments.html" th:href="@{/comments(prodId=${prod.id})}" th:unless="${#lists.isEmpty(prod.comments)}">view</a>
 2 th:switch 和 th:case
 3 
 4 <div th:switch="${user.role}">
 5   <p th:case="'admin'">User is an administrator</p>
 6   <p th:case="#{roles.manager}">User is a manager</p>
 7 </div>
 8 
 9 <div th:switch="${user.role}">
10   <p th:case="'admin'">User is an administrator</p>
11   <p th:case="#{roles.manager}">User is a manager</p>
12   <p th:case="*">User is some other thing</p>
13 </div>

七、坑

  总结一下在使用过程中遇到的坑:

  1 获取项目根目录,很多时候我们都需要获取本项目的根目录,但是使用的代码是以下代码才能获得:

<script th:inline="javascript" type="text/javascript">
    var ctx=[[${#httpServletRequest.getContextPath()}]];
</script>

   注意以上代码,如果需要在自定义的javascript中使用thymeleaf表达式,则需要将script声明一下:th:inline="javascript"。

  2 获取图片路径,当我们使用thymeleaf的时候一定要注意单、双引号的区别,不然是无法获取到对应的值或者路径的:

<span class="img" th:style="'background-image: url('+@{/images/news/}+${top4News[2].originArticleId}+'/1.jpg'+');'"></span>

   请注意以上代码:当我们要在backgroud-image这个标签下引用对应路径的img时:

    首先使用th:style进行修饰。

    然后在background-image标签前后一定要加单引号,否则不会起作用:

'background-image:xxx'

     接着就是在url里面拼接你的img路径,请注意url('xxx'),也有单引号!

    最后才能通过此路径获取到相应的图片。

八、总结

  在使用thymeleaf的过程中,遇到了一些坑,希望大家在这样的坑中少走一些弯路。

posted @ 2018-04-19 16:31  老王和小杨  阅读(14279)  评论(1编辑  收藏