Thymeleaf Practical Examples

1 Introduction

I have been using Freemarker before, and I know but not familiar with Thymeleaf. Recently, because other project teams want to quickly build the background, they used a three-party framework to use Thymeleaf, so I learned more about it.

It is found that Thymeleaf is more like a front-end template language, so it has better compatibility with static pages. That is, if it is a Freemarker template file, the browser cannot parse it, and it will make an error directly. With the Thymeleaf template file, if it is not parsed, the browser can also parse it. There is basically no problem with the basic style, but the data cannot be parsed.

Because Thymeleaf uses attributes, there are a lot less tags like Freemarker, so the syntax looks more concise.

This article mainly records some commonly used functions in Thymeleaf, so that you can see what these things mean.

2. Start

Using Thymeleaf in SpringBoot is very simple, just add the following dependencies:

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

Then, it's basically the same as using JSP, except the syntax is different.

The default configuration of SpringBoot Thymeleaf will go to the templates of the classpath to find the template file. Unlike the default suffix ftl of Freemarker, the html suffix used directly by Thymeleaf is to be recognized by the browser even if it cannot be parsed.

Next add a 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";
    }
}

Then add an index.html file:

<!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>

If you are familiar with template files, whether it is a front-end template or a back-end template, you can roughly guess what the above template means at a glance.

Thymeleaf binds the text attribute of the label through th:text, which is to set the text content for the label. Where th is the abbreviation of Thymeleaf, and text represents the text attribute.

In addition to using th:text, you can also use th:utext. The most important thing about th:utext is that you can set text with html tags

3. List Traversal

@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 traversal

@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 is the execution of the condition, unless is not the meaning of else, but the execution of the condition is not met.

Thymeleaf supports switch, which avoids writing multiple if statements.

6. @

Friends who have used JSP know that the path of JSP is really inconvenient, and you have to splicing it yourself, although you can also directly add interceptors and tool classes to deal with it.

Thymeleaf provides @, but we don't need to splicing website prefixes, mainly to deal with the context part.

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

7. th:object

th:object provides an access method that omits the object prefix, which is clear from the example.

@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>

The above two binding methods are completely equivalent.

8. Tool approach

@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>

Note that the millisecond of dates only gets the milliseconds, not the timestamp.

There are a lot of such tool class methods, you can refer to the official one for details: Thymeleaf tool class

9. include replace insert

When processing pages, it is often necessary to introduce some public pages . In Thymeleaf, we can use include to achieve it.

Unlike JSP and Freemarker, Thymeleaf can not import the entire page, but only some fragments in the page.

In a page, we can define fragments in the following ways:

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

Fragments are imported in the following way:

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

There are some shorthands for include:

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

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

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

Let's take a look at an example to enhance understanding:

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

Define a public include file 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>

Import page:

<!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>

The page after Thymeleaf renders:

<!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>

We can briefly summarize:

  1. th:insert: keep the main tag of itself and th:fragment
  2. th:replace: keep only the main tag of th:fragment
  3. th:include: keep only its own main tag

10. Handling local files

In addition to being used in the web, we also use it as a local tool:

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));
    }
}

It may be necessary to introduce the ognl package separately:

<dependency>
    <groupId>ognl</groupId>
    <artifactId>ognl</artifactId>
    <version>3.2.18</version>
</dependency>
{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324133657&siteId=291194637