Thymeleaf实用实例

1. 简介

之前一直使用Freemarker,对Thymeleaf了解但是不熟悉,最近因为其他项目组他们要快速搭建后台,使用了一个三方的框架用到了Thymeleaf,所以进一步了解了一些。

发现Thymeleaf更加像前端的模板语言,所以对静态页面有更好的兼容性,就是,如果是Freemarker模板文件,浏览器是解析不了的,会直接出错。而使用Thymeleaf模板文件,如果没有解析,浏览器也能解析,基本样式基本没有问题,只是不能解析数据。

因为Thymeleaf使用属性,少了很多像Freemarker的tag,这样语法上看起来也更加简介一些。

这篇文章主要记录一下Thymeleaf中一些常用的功能,以便于看到这些东西知道是什么意思。

2. 开始

在SpringBoot中使用Thymeleaf非常简单,只需要添加下面的依赖就可以了:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

然后,基本就和使用JSP一样,除了语法不同。

SpringBoot Thymeleaf默认配置会去classpath的templates去找模板文件,和Freemarker默认的后缀ftl不同,Thymeleaf直接使用的html后缀,就是为了就算不能解析,浏览器也能识别。

接下来添加一个Controller:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/data")
public class DataController {

    @RequestMapping("/index")
    public String show(Model model){
        model.addAttribute("id","10001");
        model.addAttribute("name","Tim");
        model.addAttribute("userhome","<a style='color:red' href='/user/10001'>Tim</a>");
        return "index";
    }
}

然后添加一个index.html文件:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Index</title>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:text="'用户ID:' + ${id}"/>
<div th:text="'用户名称:' + ${name}"/>
<div th:utext="'用户主页:' + ${userhome}"/>
</body>
</html>

如果你对模板文件熟悉,不管是前端模板,还是后端模板,基本一看就能大致猜出上面的模板是什么意思。

Thymeleaf通过th:text来绑定标签的文本属性,就是给标签设置text内容。其中th是Thymeleaf的缩写,text表示文本属性。

除了使用th:text,还可以使用th:utext,th:utext最重要的一点是可以设置带html标签的text

在这里插入图片描述

3. list遍历

@RequestMapping("/list")
public String list(Model model) {
    List<Integer> ids = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        ids.add(i) ;
    }
    model.addAttribute("ids", ids);
    return "collection/list";
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>List</title>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div>
    <table>
        <tr><td>编号</td><td>ID</td><td>是否是第偶数个元素</td><td>是否是第奇数个元素</td></tr>
        <tr th:each="id,memberStat:${ids}">
            <td th:text="${memberStat.index + 1}"/>
            <td th:text="${id}"/>
            <td th:text="${memberStat.even}"/>
            <td th:text="${memberStat.odd}"/>
        </tr>
    </table>
</div>
</body>
</html>

4. map遍历

@RequestMapping("/map")
public String map(Model model) {
    Map<Integer,String> map = new HashMap<>();
    for (int i = 0; i < 10; i++) {
        map.put(i,"VL" + i);
    }
    model.addAttribute("map", map);
    return "collection/map";
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Map</title>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div>
    <table>
        <tr><td>编号</td><td>key</td><td>value</td><td>是否是第偶数个元素</td><td>是否是第奇数个元素</td></tr>
        <tr th:each="entry,memberStat:${map}">
            <td th:text="${memberStat.index + 1}"/>
            <td th:text="${entry.key}"/>
            <td th:text="${entry.value}"/>
            <td th:text="${memberStat.even}"/>
            <td th:text="${memberStat.odd}"/>
        </tr>
    </table>
</div>
</body>
</html>

5. if unless switch

@RequestMapping("/ifel")
public String ifel(Model model) {
    model.addAttribute("score", 89);
    return "tool/ifel";
}
<body>
<div>
    <div th:if="${score ge 90}">
        A
    </div>
    <div th:if="${score lt 90 && score ge 80}">
        B
    </div>
    <div th:unless="${score ge 80}">
        C
    </div>
</div>

<div>
    <div th:switch="${score}">
        <div th:case="100">100</div>
        <div th:case="99">90</div>
        <div th:case="*">都不匹配</div>
    </div>
</div>
</body>
</html>

if是条件满足执行,unless不是else的意思,而是条件不满足执行。

Thymeleaf支持switch,这样就避免了写多个if语句了。

6. @

用过JSP的朋友都知道,JSP的路径真是一点都不方便,要自己去拼接,虽然也可以直接添加拦截器、工具类去处理。

Thymeleaf提供了@,然我们不用去拼接网站前缀,主要是处理上下文部分。

<script type="text/javascript" th:src="@{/js/jquery.js}"></script>
<a th:href="@{/user/info}">访问controller方法</a>

7. th:object

th:object提供了一种省略对象前缀的访问方式,看实例就清楚。

@RequestMapping("/info")
public String userInfo(Model model) {
    User user = new User();
    user.setId(10001);
    user.setName("轩辕雪");
    user.setAge(25);
    model.addAttribute("user", user);
    return "user/info";
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>用户信息</title>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div>
    <div th:text="'用户ID:' + ${user.id}"/>
    <div th:text="'用户姓名:' + ${user.name}"/>
    <div th:text="'用户年龄:' + ${user.age}"/>
</div>

<div th:object="${user}">
    <div th:text="'用户ID:' + *{id}"/>
    <div th:text="'用户姓名:' + *{name}"/>
    <div th:text="'用户年龄:' + *{age}"/>
</div>
</body>
</html>

上面的两种绑定方式是完全等价的。

8. 工具方法

@RequestMapping("/tool")
public String tool(Model model) {
    Set<String> set = new HashSet<>() ;
    set.add("A");

    Map<String,Integer> map = new HashMap<>();
    map.put("a",1);

    List<Integer> list = new ArrayList<>() ;
    for (int i = 0 ; i < 10 ; i ++) {
        list.add(i) ;
    }

    Integer[] array = new Integer[list.size()];
    list.toArray(array);

    model.addAttribute("list", list) ;
    model.addAttribute("set", set) ;
    model.addAttribute("map", map) ;
    model.addAttribute("array", array) ;
    model.addAttribute("now", new Date()) ;
    return "tool/tool" ;
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Index</title>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div>日期:</div>
<div>
    <div th:text="${#dates.millisecond(now)}"/>
    <div th:text="${#dates.format(now,'yyyy-MM-dd')}"/>
    <div th:text="${#dates.format(now,'yyyy-MM-dd HH:mm:ss')}"/>
</div>

<div>字符串:</div>
<div>
    <div th:text="${#strings.isEmpty('')}"/>
    <div th:text="${#strings.replace('$199','$','')}"/>
    <div th:text="${#strings.toUpperCase('love')}"/>
    <div th:text="${#strings.trim('   I Love You        ')}"/>
</div>

<div>其他:</div>
<div>
    <div th:text="${#sets.contains(set,'a')}"/>
    <div th:text="${#lists.size(list)}"/>
    <div th:text="${#maps.containsKey(map, 'a')}"/>
    <div th:text="${#arrays.length(array)}"/>
    <div th:text="${#aggregates.sum(array)}"/>
    <div th:text="${#numbers.formatInteger(3.1415926,3,'POINT')}"/>
    <div th:text="${#numbers.formatDecimal(3.1415926,3,'POINT',2,'COMMA')}"/>
    <div th:text="${#numbers.formatPercent(3.1415926, 3, 2)}"/>
</div>
</body>
</html>

注意dates的millisecond只是获取毫秒,而不是时间戳。

这样的工具类方法还有一大堆,具体可以参考官方的:Thymeleaf工具类

9. include replace insert

在处理页面的时候,经常需要引入一些公共页面,Thymeleaf中我们可以使用include实现。

和JSP、Freemarker不同,Thymeleaf可以不导入整个页面,而是只导入这个页面中的某些片段(fragment)

在页面中,我们可以通过下面的方式来定义片段:

<div th:fragment="page"></div>

通过下面的方式引入片段:

<div th:include="pagefile::page"></div>

include的有一些简写方式:

<!--  "::"前面是模板文件名,后面是fragement的名称 -->
<div th:include="template/pagefile::page"></div>

<!-- 省略模板文件名,只有fragment名称,则加载本页面对应的fragment -->
<div th:include="::page"></div>

<!-- 只写模板文件名,省略fragment名称,则加载整个页面 -->
<div th:include="template/nav"></div>

来一个示例看一看,加强理解:

@RequestMapping("/myinclude")
public String myinclude(Model model) {
    return "user/myinclude";
}

定义一个公共的包含文件include.html:

<head th:fragment=header(title)>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="keywords" content="">
    <meta name="description" content="">
    <title th:text="${title}"></title>
    <link rel="shortcut icon" href="favicon.ico">
</head>

<div th:fragment="footer">
    <script th:src="@{/js/jquery.min.js}"></script>
    <script th:src="@{/js/bootstrap.min.js}"></script>
</div>

<div clss="fragment-content-class" th:fragment="content(first,second)">
    <div th:text="'第一个参数:' + ${first} + '  第二个参数:' + ${second}"></div>
</div>

导入页面:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <th:block th:include="common/include :: header('myinclude-title')" />
</head>
<body>

<div class="page-content-class" th:insert="common/include :: content('Hello','insert')"></div>
<div class="page-content-class" th:include="common/include :: content('Hello','include')"></div>
<div class="page-content-class" th:replace="common/include :: content('Hello','replace')"></div>

<th:block th:insert="common/include :: footer" />
</body>
</html>

Thymeleaf渲染之后的页面:

<!DOCTYPE HTML>
<html>
<head>
    
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="keywords" content="">
    <meta name="description" content="">
    <title>myinclude-title</title>
    <link rel="shortcut icon" href="favicon.ico">

</head>
<body>

<div class="page-content-class"><div clss="fragment-content-class">
    <div>第一个参数:Hello  第二个参数:insert</div>
</div></div>
<div class="page-content-class">
    <div>第一个参数:Hello  第二个参数:include</div>
</div>
<div clss="fragment-content-class">
    <div>第一个参数:Hello  第二个参数:replace</div>
</div>

<div>
    <script src="/js/jquery.min.js"></script>
    <script src="/js/bootstrap.min.js"></script>
</div>
</body>
</html>

我们可以简单的小结一下:

  1. th:insert:保留自己和th:fragment的主标签
  2. th:replace:只保留th:fragment的主标签
  3. th:include:只保留自己的主标签

10. 处理本地文件

除了在Web中使用,我们也当做一个本地工具使用:

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.FileTemplateResolver;

import java.util.HashMap;
import java.util.Map;

public class ThymeleafHelper {

    private static TemplateEngine templateEngine;

    static {
        templateEngine = new TemplateEngine();
        FileTemplateResolver resolver = new FileTemplateResolver();
        resolver.setPrefix("G:\\tmp\\thymeleaf\\");
        resolver.setCharacterEncoding("UTF-8");
        resolver.setSuffix(".html");
        templateEngine.setTemplateResolver(resolver);
    }

    public static String redering(String templateFileName, Map<String,Object> data) {
        Context context = new Context();
        context.setVariables(data);
        return templateEngine.process(templateFileName, context);
    }

    public static void main(String[] args) {
        HashMap<String, Object> data = new HashMap<>();
        data.put("id","10001");
        data.put("name","Tim");
        data.put("userhome","<a style='color:red' href='/user/10001'>Tim</a>");
        System.out.println(redering("index",data));
    }
}

可能需要单独引入ognl包:

<dependency>
    <groupId>ognl</groupId>
    <artifactId>ognl</artifactId>
    <version>3.2.18</version>
</dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值