SpringBoot学习(三)—————— 框架整合其他框架之三(Thymeleaf)


前言

本篇记录我在学习SpringBoot的过程中,对Thymeleaf的学习经验;
Thymeleaf是一种

提示:以下是本篇文章正文内容,下面案例可供参考

一 Thymeleaf 介绍

1.1 概念

Thymeleaf 是一个跟 FreeMarker 类似的模板引擎,它可以完全替代 JSP 。;

1.2 特点

  • 动静结合:Thymeleaf 在有网络和无网络的环境下皆可运行,无网络显示静态内容,有网络用后台得到数据替换静态内容;

  • 与SpringBoot完美整合,springboot默认整合thymelea

二 Thymeleaf详解

1 表达式

Thymeleaf中的表达式分为三种

1.1 变量表达式

就是OGNL表达式或者Spring EL表达式(spring中在jsp页面中获取session或其他内置对象的数据)如:${session.user.name};
它们将以HTML标签的一个属性来表示:

<h5>表达式</h5>
<span>${text}</span>
<span th:text="${text}">你好 thymleaf</span>

1.2 选择表达式

也可以叫星号表达式,有点像变量表达式,不过它们用一个预先选择的对象来代替上下文变量容器(map)来执行,如: *{customer.name};被指定的对象object由th:object属性定义,
代码如下:

 <!-- user 循环对象 status 循环的序号 -->
        <tr th:each="user, status : ${users}" th:object="${user}" th:bgcolor="${status.even}? 'gray'">
            <td th:text="${status.even}">true</td>
            <td th:text="${status.odd}">true</td>
            <td th:text="${status.index}">0</td>
            <td th:text="${status.count}">1</td>
            <td th:text="${user.id}">1</td>
            <td th:text="*{name}">zhangsan</td>
            <td th:text="*{userName}">张三</td>
            <td th:text="${user.age}">20</td>
            <td th:text="${user.sex} == 1 ? '' : ''"></td>
            <td th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}">1980-02-30</td>

            <td th:text="${user.note}">1</td>
            <td>
                <!--<a href="">删除</a>-->
                <a th:href="@{delete(id=${user.id}, userName= *{userName})}">删除</a>
                <!-- 字符串替换 -->
                <a th:href="|/update/${user.id}|">修改</a>
                <!-- 字符串拼接 -->
                <a th:href="'approve/' + ${user.id}">审核</a>
            </td>
        </tr>

1.3 URL表达式

  • URL表达式指的是把一个有用的上下文或回话信息添加到URL,这个过程经常被叫做URL重写
  • URL还可以设置参数: @{/order/details(id=${orderId}, name=*{name})
1.3.1 url表达式
<a th:href="@{/delete(id=${user.id}, userName=*{userName})}">删除</a>
1.3.2 文本替换
<a th:href="|/update/${user.id}|">修改</a
1.3.2 字符串拼接
<a th:href="'/approve/' + ${user.id}">审核</a>

1.4 表达式常见用法

字面(Literals)

  • 文本文字(Text literals): ‘one text’, ‘Another one!’,…
  • 数字文本(Number literals): 0, 34, 3.0, 12.3,…
  • 布尔文本(Boolean literals): true, false
  • 空(Null literal): null文字标记(Literal tokens): one, sometext, main,…
  • 文本操作(Text operations)
  • 字符串连接(String concatenation): +
  • 文本替换(Literal substitutions): |The name is ${name}|
  • 算术运算(Arithmetic operations)
  • 二元运算符(Binary operators): +, -, *, /, %
  • 减号(单目运算符)Minus sign (unary operator): -
  • 布尔操作(Boolean operations)
  • 二元运算符(Binary operators): and, or
  • 布尔否定(一元运算符)Boolean negation (unary operator): !, not
  • 比较和等价(Comparisons and equality)
  • 比较(Comparators): >, <, >=, <= (gt, lt, ge, le)
  • 等值运算符(Equality operators): ==, != (eq, ne)
  • 条件运算符(Conditional operators)
  • If-then: (if) ? (then)
  • If-then-else: (if) ? (then) : (else)
  • Default: (value) ?: (defaultvalue)

1.5 常用th标签

关键字功能介绍案例
th:text文本替换< p th:text="${collect.description}">description< /p >
th:id替换id< input th:id="‘xxx’ + ${collect.id}"/ >
th:utext支持html的文本替换< p th:utext="${htmlcontent}">conten< /p >
th:object替换对象< div th:object="${session.user}">
th:value属性赋值< input th:value="${user.name}" />
th:with变量赋值运算< div th:with=“isEven=${prodStat.count}%2==0”>< /div>
th:style设置样式th:style="‘display:’ + @{(${sitrue} ? ‘none’ : ‘inline-block’)} + ‘’"
th:onclick点击事件th:οnclick="‘getCollect()’"
th:each属性赋值tr th:each=“user,userStat:${users}”>
th:if判断条件< a th:if="${userId == collect.userId}" >
th:unless和th:if判断相反< a th:unless="${userId == collect.userId}" >
th:href链接地址<a th:href="
th:switch多路选择 配合th:case使用< div th:switch="${user.role}"
th:caseth:switch的一个分支< p th:case="‘admin’">User is an administrator< /p>
th:fragment布局标签,定义一个代码片段,方便其它地方引用< div th:fragment=“alert”>
th:include布局标签,替换内容到引入的文件< head th:include=“layout :: htmlhead” th:with=“title=‘xx’”>< /head>
th:replace布局标签,替换整个标签到引入的文件< div th:replace=“fragments/header :: title”>< /div>
th:selectedselected选择框 选中th:selected="( {configObj.dd})"
th:src图片类地址引入< img class=“img-responsive” alt=“App Logo” th:src="@{/img/logo.png}" />
th:inline定义js脚本可以使用变量< script type=“text/javascript” th:inline=“javascript”>
th:action表单提交的地址< form action=“subscribe.html” th:action="@{/subscribe}">
th:remove删除某个属性< tr th:remove=“all”> 1.all:删除包含标签和所有的孩子。2.body:不包含标记删除,但删除其所有的孩子。3.tag:包含标记的删除,但不删除它的孩子。4.all-but-first:删除所有包含标签的孩子,除了第一个。5.none:什么也不做。这个值是有用的动态评估。
th:attr设置标签属性,多个属性可以用逗号分隔th:attr=“src=@{/image/aa.jpg},title=#{logo}”,此标签不太优雅,一般用的比较少。

1.6 基本用法

1.6.1 赋值、字符串拼接
<a th:href="|/update/${user.id}|">修改</a>
<a th:href="'/approve/' + ${user.id}">审核</a>
1.6.2 条件判断if/unless

if是条件成立是生效,unless是条件不成立是生效,两者恰好相反

<h5>if指令</h5>
<a th:if="${users.size() > 0}">查询结果存在</a><br>
<a th:if="${users.size() <= 0}">查询结果不存在</a><br>
<a th:unless="${session.user != null}" href="#">登录</a><br>
1.6.3 for循环
<!-- user 循环对象 status 循环的序号 -->
        <tr th:each="user, status : ${users}" th:object="${user}" th:bgcolor="${status.even}? 'gray'">
            <td th:text="${status.even}">true</td>
            <td th:text="${status.odd}">true</td>
            <td th:text="${status.index}">0</td>
            <td th:text="${status.count}">1</td>
            <td th:text="${user.id}">1</td>
            <td th:text="*{name}">zhangsan</td>
            <td th:text="*{userName}">张三</td>
            <td th:text="${user.age}">20</td>
            <td th:text="${user.sex} == 1 ? '' : ''"></td>
            <td th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}">1980-02-30</td>

            <td th:text="${user.note}">1</td>
            <td>
                <!--<a href="">删除</a>-->
                <a th:href="@{delete(id=${user.id}, userName= *{userName})}">删除</a>
                <!-- 字符串替换 -->
                <a th:href="|/update/${user.id}|">修改</a>
                <!-- 字符串拼接 -->
                <a th:href="'approve/' + ${user.id}">审核</a>
            </td>
        </tr>
1.6.4 status状态变量
  • index:当前迭代对象的index(从0开始计算)
  • count: 当前迭代对象的index(从1开始计算)
  • size:被迭代对象的大小
  • current:当前迭代变量
  • even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算)
  • first:布尔值,当前循环是否是第一个
  • last:布尔值,当前循环是否是最后一个
1.6.5 内联文本

以**[[…]]**方式表示,使用时必须使用“th:inline=”text”激活,th:inline可以在
父级标签内使用,甚至作为body的标签。内联文本尽管比th:text的代码少,不利于原型显示。使用的内容必须是后端返回的model总有的内容;

  • 在thymeleaf指令中显示
<h6 th:text="${text}">静态内容</h6>
  • 使用内联文本显示model attribute
<h5>内联文本</h5>
<div>
   <h6 th:inline="text">[[${text}]]</h6>
   <h6 th:inline="none">[[${text}]]</h6>
   <h6>[[${text}]]</h6>
</div>

**PS:**能用th指令就用替换指令

1.6.6 内联文本

与内联文本相似,以th:inline=”text/javascript/none”激活,内容是js脚本。拥有js脚本的能力;

<h5>内联js</h5>
<script th:inline="javascript">
var text = '[[${text}]]';
console.log(text);
</script>
1.6.7 内嵌对象

Thymeleaf提供了了一系列Utility对象(内置于Context中),可以通过**# + 对象名**的方式直接调用其中的方法。

对象功能
datesjava.util.Date**的功能方法类。
calendars类似#dates,面向java.util.Calendar
numbsers格式化数字的功能方法类
strings字符串对象的功能类
objects对objects的功能类操作。
bools对布尔值求值的功能方法。
arrays对数组的功能类方法。
lists/sets/maps/对list/set/map功能类方法
1.6.8 布局

通过footer标签定义页面;

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
	<body>
		<footer th:fragment="copy(title)">
			&copy; 2020 开课吧版权所有<br>
			<span th:text="${title}">title footer</span>
		</footer>
	</body>
</html>

然后,在页面任何地方引入:

<h5>thymeleaf布局</h5>
<div th:insert="footer :: copy('开课吧1')"></div>
<div th:replace="footer :: copy('开课吧2')"></div>
<div th:include="footer :: copy('开课吧3')"></div>
  • th:insert :保留自己的主标签,保留th:fragment的主标签。
  • th:replace :不要自己的主标签,保留th:fragment的主标签。
  • th:include :保留自己的主标签,不要th:fragment的主标签。

三 Thymeleaf入门案例

1启动器

Thymelea启动器在依赖坐标

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

2 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kaikeba</groupId>
    <artifactId>sb-thymeleaf-01</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.11.RELEASE</version>
    </parent>

    <dependencies>

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

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

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

        <!-- tk-mybatis 非官方提供 手动控制版本 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
    </dependencies>

</project>

3 配置文件

application.properties

	server.port=8080
	logging.level.com.kaikeba=debug
	
	# 数据库信息
	spring.datasource.url=jdbc:mysql://localhost:3306/springboot-jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
	spring.datasource.password=root
	spring.datasource.username=root
	spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
	
	# 关闭thymeleaf缓存
	spring.thymeleaf.cache=false

4 相关的静态文件

由于springboot为thymeleaf自动添加的视图解析器会加上templates前缀,所以我们的所有静态文件都必须在**/resources/templates/** 下,
在这里插入图片描述
定义的布局footer.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
    <footer th:fragment="copy(title)">
        &copy;2020开课吧版权所有<br/>
        <span th:text="${title}">title footer</span>
    </footer>
</body>
</html>

测试的temp.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>Thymeleaf布局</h2>
<!-- 把footer标签添加到主(父)标签里面 -->
<div th:insert="footer :: copy('开课吧1')"></div>
<!-- 直接替换主(父)标签 -->
<div th:replace="footer :: copy('开课吧22')"></div>
<!-- 直接把内容覆盖到主(父)标签的内容中 -->
<div th:include="footer :: copy('开课吧333')"></div>

<h2>内置变量</h2>
<span th:text="${#dates.format(#dates.createNow(), 'yyyy-MM-dd HH:mm:ss')}">获取当前日期</span><br/>
<span th:text="${#strings.substring(text, 4, 6)}">截取字符串</span><br/>
<span th:text="${#strings.length(text)}"></span><br/>
<span th:text="${#strings.randomAlphanumeric(6)}">随机字符串</span><br/>
<span th:text="${#strings.equals(text, 'hello')}">equals等值判断</span><br/>

<h2>if指令</h2>
<a th:if="${users.size() > 0}"> 查询结果存在</a><br/>
<a th:if="${users.size() <= 0}">查询结果不存在</a><br/>
<a th:unless="${session.user != null}">登录</a><br/>

<h2>内联文本</h2>
<span th:text="${text}">静态内容</span>
<div>
    <h3 th:inline="text">${text}</h3>
    <h3>[[${text}]]</h3>
</div>

<h3>内联JS</h3>
<span>内容在console.log</span>
<script th:inline="javascript">
    var text = '[[${text}]]';
    console.log(text);
</script>


</body>
</html>

测试循环的user.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <title>Thymeleaf 入门案例</title>
    <meta charset="UTF-8">
    <style type="text/css">
        table {
            border-collapse: collapse;
            font-size: 15px;
            width: 80%;
            margin: auto;
        }

        table, th, td {
            border: 1px solid darkslategray;
            padding: 10px
        }
    </style>
</head>
<body>
<div style="text-align: center">
    <span style="color: darkslategray; font-size: 30px">欢迎光临</span>
    <hr/>
    <table class="list">
        <tr>
            <th>偶数行</th>
            <th>奇数行</th>
            <th>序号index</th>
            <th>序号count</th>
            <th>ID</th>
            <th>姓名</th>
            <th>用户名</th>
            <th>年龄</th>
            <th>性别</th>
            <th>生日</th>
            <th>备注</th>
            <th>操作</th>
        </tr>
        <!-- user 循环对象 status 循环的序号 -->
        <tr th:each="user, status : ${users}" th:object="${user}" th:bgcolor="${status.even}? 'gray'">
            <td th:text="${status.even}">true</td>
            <td th:text="${status.odd}">true</td>
            <td th:text="${status.index}">0</td>
            <td th:text="${status.count}">1</td>
            <td th:text="${user.id}">1</td>
            <td th:text="*{name}">zhangsan</td>
            <td th:text="*{userName}">张三</td>
            <td th:text="${user.age}">20</td>
            <td th:text="${user.sex} == 1 ? '' : ''"></td>
            <td th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}">1980-02-30</td>

            <td th:text="${user.note}">1</td>
            <td>
                <!--<a href="">删除</a>-->
                <a th:href="@{delete(id=${user.id}, userName= *{userName})}">删除</a>
                <!-- 字符串替换 -->
                <a th:href="|/update/${user.id}|">修改</a>
                <!-- 字符串拼接 -->
                <a th:href="'approve/' + ${user.id}">审核</a>
            </td>
        </tr>
    </table>
</div>

</body>
</html>

5 后台UserController

package com.kaikeba.controller;

import com.kaikeba.entity.pojo.User;
import com.kaikeba.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author sunyang
 * @date 2021/5/31 11:32
 */
@Controller
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @GetMapping("/all")
    public String searchAll(Model model) {
        List<User> all = userService.findAll();
        model.addAttribute("users", all);
        model.addAttribute("text","我这是测试th:text");
        return "user";
    }

    /**
     * @desc thymeleaf测试
     *
     * @param model
     * @return java.lang.String
     * @date 2021/5/31 16:42
     * @auther sunyang
     */
    @GetMapping("/temp")
    public String temp(Model model) {
        List<User> all = userService.findAll();
        model.addAttribute("users", all);
        model.addAttribute("text","我这是测试th:text");
        return "temp";
    }
}

6 实体类User

package com.kaikeba.entity.pojo;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;

/**
 * @author sunyang
 * @date 2021/5/31 11:30
 */
@Table(name = "tbs_user")
public class User {
    // 主键 自增
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private Date created;
    private Date updated;
    private String note;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", birthday=" + birthday +
                ", created=" + created +
                ", updated=" + updated +
                ", note='" + note + '\'' +
                '}';
    }
}

7 UserMapper

package com.kaikeba.mapper;

import com.kaikeba.entity.pojo.User;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author sunyang
 * @date 2021/5/31 11:29
 */
@Mapper
public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User> {
}

8 UserService

package com.kaikeba.service;

import com.kaikeba.entity.pojo.User;

import java.util.List;

/**
 * @author sunyang
 * @date 2021/5/31 11:29
 */
public interface UserService {
    /**
     * @return java.util.List<com.kaikeba.entity.pojo.User>
     * @desc 查询所有数据
     * @date 2021/5/31 11:31
     * @auther sunyang
     */
    List<User> findAll();
}

9 UserServiceImpl

package com.kaikeba.service.impl;

import com.kaikeba.entity.pojo.User;
import com.kaikeba.mapper.UserMapper;
import com.kaikeba.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author sunyang
 * @date 2021/5/31 11:30
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.selectAll();
    }
}

四 测试结果

1 循环

在这里插入图片描述

2 布局、内置对象和其他指令

在这里插入图片描述
内联的js:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值