编程知识 cdmana.com

Spring boot + thymeleaf, there are so many interesting details!

@[toc]
Although it's popular to separate the front and back ends , But back end templates are still very useful in some key areas , For example, email templates 、 Code templates, etc . Of course, some old project back ends still use dynamic templates .

Thymeleaf Simple and beautiful 、 Easy to understand , And perfectly support HTML5, You can open static pages directly , Do not add tags at the same time , Just enhance the properties , It also reduces the cost of learning .

So SongGe will take some time to share with you today Thymeleaf.

1. Thymeleaf brief introduction

Thymeleaf Is the new generation Java template engine , It is similar to Velocity、FreeMarker Etc Java template engine , But with tradition Java The template engine is different from ,Thymeleaf Support HTML Prototype .

It allows the front-end engineer to view the style directly in the browser , You can also let the back-end engineer view the display effect in combination with real data , meanwhile ,SpringBoot Provides Thymeleaf Automated configuration solutions , So in SpringBoot Use in Thymeleaf Very convenient .

in fact , Thymeleaf In addition to showing basic HTML , In addition to page rendering , Can also be used as a HTML Render the clip , For example, when we send emails , have access to Thymeleaf Send as email template .

in addition , because Thymeleaf The template suffix is .html, It can be opened directly by browser , therefore , It's very convenient to preview .

2. Integrate Spring Boot

2.1 Basic usage

Spring Boot The integration of Thymeleaf Very easy to , Just add... When you create the project Thymeleaf that will do :

After creation ,pom.xml Depends on the following :

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

Of course ,Thymeleaf It's not just in Spring Boot Use in , It can also be used in other places , It's just Spring Boot in the light of Thymeleaf A complete set of automatic configuration scheme is provided , The properties of this set of configuration classes are org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties in , Part of the source code is as follows :

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
        private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
        public static final String DEFAULT_PREFIX = "classpath:/templates/";
        public static final String DEFAULT_SUFFIX = ".html";
        private boolean checkTemplate = true;
        private boolean checkTemplateLocation = true;
        private String prefix = DEFAULT_PREFIX;
        private String suffix = DEFAULT_SUFFIX;
        private String mode = "HTML";
        private Charset encoding = DEFAULT_ENCODING;
        private boolean cache = true;
        //...
}
  1. First, through @ConfigurationProperties annotation , take application.properties The prefix for spring.thymeleaf The configuration of is bound to the properties in this class .
  2. The first three static Variable defines the default encoding format 、 The prefix of the view parser 、 Suffixes, etc .
  3. In the first three line configuration , You can see it ,Thymeleaf The default location of the template is resources/templates Under the table of contents , The default suffix is html .
  4. These configurations , If the developer doesn't provide , Then use default , If you provide , It's in application.properties China and Israel spring.thymeleaf Start related configuration .

And what we just mentioned ,Spring Boot by Thymeleaf The automation configuration class provided , It is org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration , Part of the source code is as follows :

@Configuration
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration {
}

You can see , In this automation configuration class , First, import. ThymeleafProperties , then @ConditionalOnClass Annotation means that when there is TemplateMode and SpringTemplateEngine Class time , The current automation configuration class will take effect , That is, as long as... Is introduced into the project Thymeleaf Dependent dependency , This configuration will take effect .

These default configurations can be used directly without any changes . If developers have special needs , Can be in application.properties In the configuration to spring.thymeleaf The properties at the beginning are just .

Next we can create Controller 了 , Actually introduce Thymeleaf After dependence , We can do nothing to configure . New IndexController as follows :

@Controller
public class IndexController {
    @GetMapping("/index")
    public String index(Model model) {
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User u = new User();
            u.setId((long) i);
            u.setName("javaboy:" + i);
            u.setAddress(" Shenzhen :" + i);
            users.add(u);
        }
        model.addAttribute("users", users);
        return "index";
    }
}
public class User {
    private Long id;
    private String name;
    private String address;
    // Omit  getter/setter
}

stay IndexController Returns the logical view name + data , The logical view is called index , We need to be in resources/templates A directory named index.html Of Thymeleaf Template file .

  • establish Thymeleaf
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<table border="1">
    <tr>
        <td> Number </td>
        <td> user name </td>
        <td> Address </td>
    </tr>
    <tr th:each="user : ${users}">
        <td th:text="${user.id}"></td>
        <td th:text="${user.name}"></td>
        <td th:text="${user.address}"></td>
    </tr>
</table>
</body>
</html>

stay Thymeleaf in , adopt th:each Instruction to traverse a set , The data is displayed through th:text Instructions to implement ,

Be careful index.html At the top, introduce thymeleaf The name space ( There is no mandatory requirement in the latest edition ).

When the configuration is complete , You can start the project , visit /index Interface , You can see the data in the set :

2.2 Manual rendering

What we said earlier is to return to one Thymeleaf Templates , We can also manually render Thymeleaf Templates , This is usually useful when sending emails , For example, I am in resources/templates Create a new mail template in the directory , as follows :

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>hello  welcome  <span th:text="${username}"></span> Join in  XXX  The group , Your entry information is as follows :</p>
<table border="1">
    <tr>
        <td> Position </td>
        <td th:text="${position}"></td>
    </tr>
    <tr>
        <td> salary </td>
        <td th:text="${salary}"></td>
    </tr>
</table>
<img src="http://www.javaboy.org/images/sb/javaboy.jpg" alt="">
</body>
</html>

This one HTML In the template , There are several variables , We're going to put this HTML Template rendering into a String character string , Then send the string by email , So how to render manually ?

@Autowired
TemplateEngine templateEngine;
@Test
public void test1() throws MessagingException {
    Context context = new Context();
    context.setVariable("username", "javaboy");
    context.setVariable("position", "Java The engineer ");
    context.setVariable("salary", 99999);
    String mail = templateEngine.process("mail", context);
    // Omit email 
}
  1. When rendering , We need to first inject a TemplateEngine object , This object is in Thymeleaf In the automatic configuration class of ( That is, when we introduce Thymeleaf After dependence , This is the case ).
  2. And then construct a Context Object to hold variables .
  3. call process Method to render , The return value of this method is after rendering HTML character string , Then we send this string out .

3. Thymeleaf details

The first two cases let the partners generally understand that Spring Boot How to use Thymeleaf, Next , SongGe will introduce in detail Thymeleaf Some specific uses of itself .

3.1 Standard expression syntax

3.1.1 Simple expressions

${...}

Use it directly th:xx = "${}" Get object properties . This has been demonstrated in the previous case , I won't repeat .

*{...}

Can be like ${...} The use of , It can also be done through th:object Get objects , And then use th:xx = "*{}" Get object properties , This style of shorthand is extremely refreshing , It is recommended that you use .

<table border="1" th:object="${user}">
<tr>
    <td> user name </td>
    <td th:text="*{username}"></td>
</tr>
<tr>
    <td> Address </td>
    <td th:text="*{address}"></td>
</tr>
</table>

#{...}

The usual internationalization attribute :#{...} Used to obtain international language translation values .

stay resources Create two new files in the directory :messages.properties and messages_zh_CN.properties, The contents are as follows :

messages.properties:

message = javaboy

messages_zh_CN.properties:

message =  A little rain in Jiangnan 

And then in thymeleaf I quote message, The system will display different values according to the language environment of the browser :

<div th:text="#{message}"></div>

@{...}

  • Quote absolutely URL:
<script type="text/javascript" th:src="@{http://localhost:8080/hello.js}"></script>

Equivalent to :

<script type="text/javascript" src="http://localhost:8080/hello.js"></script>
  • Context sensitive URL:

First, in the application.properties Middle configuration Spring Boot The context of , To facilitate testing :

server.servlet.context-path=/myapp

Reference path :

<script type="text/javascript" th:src="@{/hello.js}"></script>

Equivalent to :

<script type="text/javascript" src="/myapp/hello.js"></script>
  • relative URL:

This relative is relative to the server URL, For example, the following quote :

<script type="text/javascript" th:src="@{~/hello.js}"></script>

Equivalent to :

<script type="text/javascript" src="/hello.js"></script>

The context of the application /myapp Will be ignored .

  • The agreement is opposite URL:
<script type="text/javascript" th:src="@{//localhost:8080/hello.js}"></script>

Equivalent to :

<script type="text/javascript" src="//localhost:8080/hello.js"></script>
  • Parameterized URL:
<script type="text/javascript" th:src="@{//localhost:8080/hello.js(name='javaboy',age=99)}"></script>

Equivalent to :

<script type="text/javascript" th:src="//localhost:8080/hello.js?name=javaboy&age=99"></script>

~{...}

The fragment expression is Thymeleaf One of the characteristics of , Fine grained can reach the label level , This is a JSP unattainable . Fragment expressions have three kinds of Syntax :

  • ~{ viewName }: Means to introduce a full page
  • ~{ viewName ::selector}: To search for a fragment on a specified page , among selector Can be a fragment name 、jquery Selector, etc
  • ~{ ::selector}: Search for in the current page

A simple example .

stay resources/templates New under the directory my_fragment.html file , The contents are as follows :

<div th:fragment="javaboy_link"><a href="http://www.javaboy.org">www.javaboy</a></div>
<div th:fragment="itboyhub_link"><a href="http://www.itboyhub.com">www.itboyhub.com</a></div>

There are two div, adopt th:fragment To define the fragment , Two div Each has a different name .

Then reference the fragment in another page :

<table border="1" th:object="${user}" th:fragment="aaa">
<tr>
    <td> user name </td>
    <td th:text="*{username}"></td>
</tr>
<tr>
    <td> Address </td>
    <td th:text="*{address}"></td>
</tr>
</table>
<hr>
<div th:replace="my_fragment.html"></div>
<hr>
<div th:replace="~{my_fragment.html::javaboy_link}"></div>
<hr>
<div th:replace="~{::aaa}"></div>

adopt th:replace To quote fragments . The first one is a reference complete my_fragment.html page ; The second is a reference my_fragment.html The called javaboy_link Fragments of ; The third refers to a reference to the current page named aaa Fragments of , That's the one above table.

3.1.2 Literal

These are characters that can be written directly into expressions , There are mainly the following :

  • The literal amount of the text : ‘one text’, ‘Another one!’,…
  • Number literal quantity : 0, 34, 3.0, 12.3,…
  • Boolean literal : true, false
  • Null Literal : null
  • A literal mark :one, sometext, main,…

Case study :

<div th:text="' This is a   The literal amount of the text ( The space )'"></div>
<div th:text="javaboy"></div>
<div th:text="99"></div>
<div th:text="true"></div>

If the text is in English , And it doesn't contain spaces 、 A comma, etc , You don't have to use single quotes .

3.1.3 Text operations

Text can use + Splicing .

<div th:text="'hello '+'javaboy'"></div>
<div th:text="'hello '+${user.username}"></div>

If the string contains variables , You can also use another simple way , It's called literal displacement , use | Instead of '...' + '...', as follows :

<div th:text="|hello ${user.username}|"></div>
<div th:text="'hello '+${user.username}+' '+|Go ${user.address}|"></div>

3.1.4 Arithmetic operations

Arithmetic operations include :+, -, *, / and %.

<div th:with="age=(99*99/99+99-1)">
    <div th:text="${age}"></div>
</div>

th:with A local variable is defined age, Where it is div You can use this local variable in .

3.1.5 Boolean operation

  • Binary operator :and, or
  • Buffy ( Unary operator ):!, not

Case study :

<div th:with="age=(99*99/99+99-1)">
    <div th:text="9 eq 9 or 8 ne 8"></div>
    <div th:text="!(9 eq 9 or 8 ne 8)"></div>
    <div th:text="not(9 eq 9 or 8 ne 8)"></div>
</div>

3.1.6 Compare and equal

The value in the expression can be used >, <, >= and <= Symbolic comparison .== and != The operator is used to check for equality ( Or not equal ). Be careful XML Regulations < and > Tags cannot be used for attribute values , So we should translate them into &lt; and &gt;.

If you don't want to escape , You can also use aliases :gt (>);lt (<);ge (>=);le (<=);not (!). also eq (==), neq/ne (!=).

give an example :

<div th:with="age=(99*99/99+99-1)">
    <div th:text="${age} eq 197"></div>
    <div th:text="${age} ne 197"></div>
    <div th:text="${age} ge 197"></div>
    <div th:text="${age} gt 197"></div>
    <div th:text="${age} le 197"></div>
    <div th:text="${age} lt 197"></div>
</div>

3.1.7 Conditional operator

Similar to us Java The binomial operator in .

<div th:with="age=(99*99/99+99-1)">
    <div th:text="(${age} ne 197)?'yes':'no'"></div>
</div>

among ,: The following part can be omitted , If you omit , At the same time, the calculation result is false when , Will return null.

3.1.8 Built-in objects

Basic built-in objects :

  • #ctx: Context object .
  • #vars: Context variable .
  • #locale: Context locale .
  • #request:( Only in Web In the context of )HttpServletRequest object .
  • #response:( Only in Web In the context of )HttpServletResponse object .
  • #session:( Only in Web In the context of )HttpSession object .
  • #servletContext:( Only in Web In the context of )ServletContext object .

You can access these built-in objects on the page , A simple example :

<div th:text='${#session.getAttribute("name")}'></div>

Built in utility objects :

  • #execInfo: Information about the template being processed .
  • #messages: Method to get externalized message in variable expression , And use #{…} Grammar is obtained in the same way .
  • #uris: escape URL / URI Part of the way
  • #conversions: Perform the configured transformation service ( If there is ) Methods .
  • #dates:java.util.Date Object method : format , Component extraction, etc
  • #calendars: Be similar to #dates however java.util.Calendar object .
  • #numbers: Methods used to format digital objects .
  • #strings:String Object method :contains,startsWith,prepending / appending etc.
  • #objects: Methods of general objects .
  • #bools: The method of Boolean evaluation .
  • #arrays: Array methods .
  • #lists: List method .
  • #sets: The way to assemble .
  • #maps: Map method .
  • #aggregates: A method of creating an aggregate on an array or collection .
  • #ids: Deal with potentially repetitive id Method of attribute ( for example , As a result of iteration ).

Here are some built-in objects and tool methods , It's easy to use , If you are using IntelliJ IDEA, Will automatically prompt the method in the object , Very convenient .

give an example :

<div th:text="${#execInfo.getProcessedTemplateName()}"></div>
<div th:text="${#arrays.length(#request.getAttribute('names'))}"></div>

3.2 Setting property values

This is for HTML Element sets the attribute value . You can set more than one at a time , Use... Between multiple , Separate .

for example :

<img th:attr="src=@{/1.png},title=${user.username},alt=${user.username}">

It will be rendered as :

<img src="/myapp/1.png" title="javaboy" alt="javaboy">

Of course, this setting method is not very beautiful , It's not very readable either .Thymeleaf Also supports in every native HTML Add... Before the attribute th: Prefix to use dynamic values , Like this :

<img th:src="@{/1.png}" th:alt="${user.username}" th:title="${user.username}">

It looks clearer in this way , The rendering effect is the same as before .

In the case above alt and title There are two special properties , You can set it all at once , Like this :

<img th:src="@{/1.png}" th:alt-title="${user.username}">

This is equivalent to the previous settings .

3.3 Traverse

Array / aggregate /Map/Enumeration/Iterator Traversal is also a very common requirement ,Thymeleaf Pass through th:each To implement traversal , Like this :

<table border="1">
    <tr th:each="u : ${users}">
        <td th:text="${u.username}"></td>
        <td th:text="${u.address}"></td>
    </tr>
</table>

users Is the set to traverse / Array ,u It's a single element in the set .

When traversing , We may need to get the traversal state ,Thymeleaf It also supports this :

  • index: The current traversal index , from 0 Start .
  • count: The current traversal index , from 1 Start .
  • size: The number of elements in the traversed variable .
  • current: The traversal variable of each traversal .
  • even/odd: Is the current traversal even or odd .
  • first: Whether this is the first traversal .
  • last: Whether the current is the last traversal .

u hinder state Indicates traversal state , By traversing the state, you can refer to the above properties .

<table border="1">
    <tr th:each="u,state : ${users}">
        <td th:text="${u.username}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
    </tr>
</table>

3.4 Branch statement

Show only odd traversal , have access to th:if, as follows :

<table border="1">
    <tr th:each="u,state : ${users}" th:if="${state.odd}">
        <td th:text="${u.username}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
    </tr>
</table>

th:if Not only Boolean values are accepted , Other types of values are also accepted , For example, the following values will be determined as true:

  • If the value is Boolean , And for true.
  • If the value is a number , And not for 0.
  • If the value is a character , And not for 0.
  • If the value is a string , And not for “false”, “off” perhaps “no”.
  • If the value is not Boolean , Numbers , Character or string .

But if the value is null,th:if Will evaluate to false.

th:unless The condition of judging is the same as th:if The opposite .

<table border="1">
    <tr th:each="u,state : ${users}" th:unless="${state.odd}">
        <td th:text="${u.username}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
    </tr>
</table>

This display is the opposite of the above .

When there are more possibilities , You can also use switch:

<table border="1">
    <tr th:each="u,state : ${users}">
        <td th:text="${u.username}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
        <td th:switch="${state.odd}">
            <span th:case="true">odd</span>
            <span th:case="*">even</span>
        </td>
    </tr>
</table>

th:case="*" It means the default option .

3.5 The local variable

We have already talked about this , Use th:with You can define a local variable .

3.6 inline

We can use properties to put data into the page template , But a lot of times , The inline approach looks more intuitive , Like this :

<div>hello [[${user.username}]]</div>

It's also more natural to do stitching in an inline way .

[[...]] Corresponding to th:text ( It turns out to be an escape HTML),[(...)] Corresponding to th:utext, It doesn't perform anything HTML escape .

Like this :

<div th:with="str='hello <strong>javaboy</strong>'">
    <div>[[${str}]]</div>
    <div>[(${str})]</div>
</div>

The final display effect is as follows :

But there's a problem with the inline approach . We use Thymeleaf One of the advantages is that you can see the display directly in the browser without dynamic rendering , This is true when we use attribute configuration , But if we use inline , Various expressions will be displayed directly in the static web page .

It can also be in js perhaps css Use inline in , With js For example , Use as follows :

<script th:inline="javascript">
    var username=[[${user.username}]]
    console.log(username)
</script>

js We need to go through th:inline="javascript" Turn on inline .

4. Summary

All right. ,Thymeleaf It's almost what you introduced , It should be OK to deal with daily work . Yes Thymeleaf Interested partners .

Requirements document address :gitee.com/lenve/javadoc

Click to see more

版权声明
本文为[osc_ 1i2u0r5x]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201225111312337G.html

Scroll to Top