Spring笔记(10) Spring Boot 整合 Thymeleaf 教程

Thymeleaf 是目前较为流行的视图层技术,我从来没用过,然后通过学习,发现挺好用。就我理解,通过它,很多前端要实现的逻辑和处理,可以放到后端,感觉比较适合我,可能我一直想实现的「在线工具」,会通过它做出来。

本文是 Spring boot 结合 Thymeleaf 的基础使用。内容主要参考 Spring全家桶,版权说明在文末。

还是有点无语,我的 Gitchat 会员马上到期,最新的会员只能免费看 Chat ,不包含专栏内容。这我倒是能理解,但是以前购买过的专栏,不能再看,这还是有点无语,自己花钱购买的内容,到期后就不能看了,知识付费也不是这样玩的。所以没办法,只能将一些内容,以博客的形式的输出,不然下次忘记了,想找都找不到。

创建 Spring boot

创建 Spring boot 项目倒是比较简单,我一般都是官方网站 搭建,然后下载。

先在 pom.xml 添加好依赖。

	<!--Thymeleaf 模版-->
		<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>
	<!--spring boot 模版-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

接着在 resources 路径下创建 application.yml。

spring:
  thymeleaf:
    prefix: classpath:/templates/     #模版路径
    suffix: .html                     #模版后缀
    servlet:
      content-type: text/html         #设置 Content-type
    encoding: UTF-8                   #编码方式
    mode: HTML5                       #校验 HTML5 格式
    cache: false                      #关闭缓存,在开发过程中可立即看到页面修改结果

下面就是上代码,上案例,有点特别要注意,前端看到的内容,也就是 .html 都不是直接在浏览器打开的。而是 Thymeleaf 渲染出来的,是动态变化的。

我们在浏览器打开的地址,都只是 Controller 定义的接口地址而已。

Thymeleaf 常用标签

  • th:text

th:text 用于文本显示,将业务数据的值填充到 HTML 标签中

    @GetMapping("/a")
    public ModelAndView test01(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name","张三");
        modelAndView.setViewName("test01");
        return modelAndView;
    }

新建 test01.html ,里面内容如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p th:text="${name}">Hello World</p>
</body>
</html>

运行程序,然后在浏览器输入 localhost:8080/a,页面内容就被渲染成 张三,并不是静态默认的 Hello World 。可以发现,我并不是直接在浏览器上输入地址 localhost:8080/test01.html

  • th:if

th:if 用于条件判断,对业务数据的值进行判断,如果条件成立则显示内容,否则不显示,具体使用如下所示。

    @GetMapping("/b")
    public ModelAndView test02(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("score",90);
        modelAndView.setViewName("test02");
        return modelAndView;
    }

test02.html

<body>
    <p th:if="${score>=90}">优秀</p>
    <p th:if="${score<90 && score>=80}">良好</p>
</body>
  • th:switch th:case

th:switch th:case 两个结合起来使用,用作多条件等值判断,逻辑与 Java 中的 switcht-case 一致,当 switch 中的业务数据值等于某个 case 值时,就显示这个 case 对应的内容,具体使用如下所示。

  @GetMapping("/c")
    public ModelAndView test03(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("studentId",1);
        modelAndView.setViewName("test03");
        return modelAndView;
    }
<body>
    <div th:switch="${studentId}">
        <p th:case="1">张三</p>
        <p th:case="2">李四</p>
        <p th:case="3">王五</p>
    </div>
</body>

页面上会显示 张三。

  • th:action

th:action 用来指定请求的 URL,相当于 form 表单中的 action 属性,具体使用如下所示。

既然用到了 login.html 表单,下面创建了一个

<form th:action="@{/e}" method="post">
    用户名:<input type="text" name="userName"/><br/>
    密码:<input type="password" name="password"/><br/>
    <input type="submit" value="登录"/>
</form>

可以找到这个静态 html 打开看看

接着写一个用来显示 login.html 的接口,正如前面提到的,.html 不能直接显示,需要用 Thymeleaf 来渲染显示,因为里面有动态参数。

   @GetMapping("/d")
    public ModelAndView tesshowHtmlt03(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("login");
        return modelAndView;
    }

因为 action 指向的是目标 URL ,所以我还得写个接收表单参数的接口,同时地址要和 action 指向的一样。

注意区分 @ 和 $

  @PostMapping("/e")
    public String e(@RequestParam("userName") String userName,@RequestParam("password") String password){
        System.out.println(userName+"  "+password);
        return "login";
    }
  • th:each

th:each 用来遍历集合,具体使用如下所示。

结合 Lombok 创建 User 实体类,首先在 pom.xml 中添加 Lombok 依赖。

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
</dependency>

实体类

@Data
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer gender;
}
@GetMapping("/f")
    public ModelAndView f(){
        List<User> list = new ArrayList<>();
        list.add(new User(1L,"张三",1));
        list.add(new User(2L,"李四",0));
        list.add(new User(3L,"王五",1));
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test04");
        modelAndView.addObject("list",list);
        return modelAndView;
    }

test04.html

<h1>用户信息</h1>
<table>
    <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>性别</th>
    </tr>
    <tr th:each="user:${list}">
        <td th:text="${user.id}"></td>
        <td th:text="${user.name}"></td>
        <td th:if="${user.gender == 1}">男</td>
        <td th:if="${user.gender == 0}">女</td>
    </tr>
</table>
  • th:value

th:value 用作给标签赋值,具体使用如下所示。

   @GetMapping("/g")
    public ModelAndView g(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test05");
        modelAndView.addObject("value","Spring Boot");
        return modelAndView;
    }

test05.html

<input th:value="${value}"/>
  • th:src

th:src 用作引入静态资源,相当于 HTML 原生标签 img、script 的 src 属性,具体使用如下所示。

这里需要注意所有的静态资源,包括图片、JavaScript 资源、CSS 资源,HTML 资源(通过 Handler 访问的除外)等都需要放置在 /resources/static 路径下才可以访问,因为 Spring Boot 默认从 static 路径下读取静态资源。

   @GetMapping("/h")
    public ModelAndView h(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test06");
        modelAndView.addObject("src","/image/1.jpeg");
        return modelAndView;
    }
  <img th:src="${src}"/>

src 的值可以从模式数据中获取,也可以在 HTML 中直接定义,如果采用这种方式,Handler 中就无需传递业务数据,如下所示。

@GetMapping("/src")
public ModelAndView src(){
  ModelAndView modelAndView = new ModelAndView();
  modelAndView.setViewName("test");
  return modelAndView;
}
<img th:src="@{../images/springboot.png}">

此时的 th:src="@{../images/springboot.png}",注意与 th:src="${src}" 的区别,如果是从业务数据中取值,则需要使用 ${} 取值,如果在静态页面直接取值则使用 @{}

  • th:href

th:href 用作设置超链接的 href,具体使用如下所示。

@GetMapping("/href")
public ModelAndView href(){
  ModelAndView modelAndView = new ModelAndView();
  modelAndView.setViewName("test");
  modelAndView.addObject("href","https://spring.io/projects/spring-boot/");
  return modelAndView;
}
<a th:href="${href}">Spring Boot</a>

这里也可以使用 Spring Boot,原理同 th:src,就不再赘述了。

  • th:selected

th:selected 用作给 HTML 元素设置选中,条件成立则选中,否则不选中,具体使用如下所示。

@GetMapping("/selected")
public ModelAndView selected(){
  List<User> list = new ArrayList<>();
  list.add(new User(1L,"张三",1));
  list.add(new User(2L,"李四",0));
  list.add(new User(3L,"王五",1));
  ModelAndView modelAndView = new ModelAndView();
  modelAndView.setViewName("test");
  modelAndView.addObject("list",list);
  modelAndView.addObject("name","李四");
  return modelAndView;
}
    <option th:each="user:${list}" th:value="${user.id}" th:text="${user.name}" th:selected="${user.name == name}"></option>

这里结合 th:each 来使用,首先遍历 list 集合动态创建 option 元素,接下来根据每次遍历出的 user.name 与业务数据中的 name 是否相等来决定是否要选择,业务数据中的 name = "李四",所以 “李四” 对应的 option 为选中状态。

  • th:attr

th:attr 用作给 HTML 标签的任意属性赋值,具体使用如下所示。

@GetMapping("/attr")
public ModelAndView attr(){
  ModelAndView modelAndView = new ModelAndView();
  modelAndView.setViewName("test");
  modelAndView.addObject("attr","Spring Boot");
  return modelAndView;
}
<input th:attr="value=${attr}"/>

这里也可以使用 <input th:attr="value=@{Spring Boot}"/>,原理同 th:src。

Thymeleaf 对象

Thymeleaf 支持直接访问 Servlet Web 原生资源,即 HttpServletRequest、HttpServletResponse、HttpSession、ServletContext 对象,具体使用如下所示。

  • #request:获取 HttpServletRequest 对象
  • #response:获取 HttpServletResponse 对象
  • #session:获取 HttpSession 对象
  • #servletContext:获取 ServletContext 对象
@GetMapping("/servlet")
public String servlet(HttpServletRequest request){
  request.setAttribute("value","request");
  request.getSession().setAttribute("value","session");
  request.getServletContext().setAttribute("value","servletContext");
  return "test";
}
<p th:text="${#request.getAttribute('value')}"></p>
<p th:text="${#session.getAttribute('value')}"></p>
<p th:text="${#servletContext.getAttribute('value')}"></p>
<p th:text="${#response}"></p>

同时 Thymeleaf 也支持直接访问 session,通过 ${session.name} 可直接获取,如果使用 ModelAndView 对象来封装视图和业务数据,在视图层业务数据也是保存在 request 对象中的,业务数据可以通过 ${#request.getAttribute('name')} 获取,也可以通过 ${name} 获取,

@GetMapping("/servlet2")
public ModelAndView servlet2(HttpSession session){
  session.setAttribute("name","李四");
  ModelAndView modelAndView = new ModelAndView();
  modelAndView.setViewName("test");
  modelAndView.addObject("name","张三");
  return modelAndView;
}
<p th:text="${name}"></p>
<p th:text="${#request.getAttribute('name')}"></p>
<p th:text="${session.name}"></p>
<p th:text="${#session.getAttribute('name')}"></p>
运行结果
张三
张三
李四
李四

Thymeleaf 除了可以访问 Servlet Web 原生资源,同时还提供了内置对象来简化视图层对于业务数据的处理,可以把内置对象简单理解为工具类,通过相关方法可以实现业务需求,常用的内置对象如下所示。

  • dates:日期格式化内置对象,参照 java.util.Date 的使用。
  • calendars:日期操作内置对象,参照 java.util.Calendar 的使用。
  • numbers: 数字格式化内置对象。
  • strings:字符串格式化内置对象,参照 java.lang.String 的使用。
  • bools:boolean 类型内置对象。
  • arrays:数组操作内置对象,参照 java.utils.Arrays 的使用。
  • lists:List 集合内置对象,参照 java.util.List 的使用。
  • sets:Set 集合内置对象,参照 java.util.Set 的使用。
  • maps:Map 集合内置对象,参照 java.util.Map 的使用。
@GetMapping("/utility")
public ModelAndView utility(){
  ModelAndView modelAndView = new ModelAndView();
  modelAndView.setViewName("test");
  modelAndView.addObject("date",new Date());
  Calendar calendar = Calendar.getInstance();
  calendar.set(2019,5,5);
  modelAndView.addObject("calendar",calendar);
  modelAndView.addObject("number",0.06);
  modelAndView.addObject("string","Spring Boot");
  modelAndView.addObject("boolean",true);
  modelAndView.addObject("array", Arrays.asList("张三","李四","王五"));
  List<User> list = new ArrayList<>();
  list.add(new User(1L,"张三",1));
  list.add(new User(2L,"李四",0));
  list.add(new User(3L,"王五",1));
  modelAndView.addObject("list",list);
  Set<User> set = new HashSet<>();
  set.add(new User(1L,"张三",1));
  set.add(new User(2L,"李四",0));
  set.add(new User(3L,"王五",1));
  modelAndView.addObject("set",set);
  Map<Long,User> map = new HashMap<>();
  map.put(1L,new User(1L,"张三",1));
  map.put(2L,new User(2L,"李四",0));
  map.put(3L,new User(3L,"王五",1));
  modelAndView.addObject("map",map);
  return modelAndView;
}
date格式化:<span th:text="${#dates.format(date,'yyyy-MM-dd')}"></span><br/>
当前日期:<span th:text="${#dates.createToday()}"></span><br/>
当前时间:<span th:text="${#dates.createNow()}"></span><br/>
calendar格式化:<span th:text="${#calendars.format(calendar,'yyyy-MM-dd')}"></span><br/>
number百分比格式化:<span th:text="${#numbers.formatPercent(number,2,2)}"></span><br/>
name是否为空:<span th:text="${#strings.isEmpty(string)}"></span><br/>
name的长度:<span th:text="${#strings.length(string)}"></span><br/>
name拼接:<span th:text="${#strings.concat('I love ',string)}"></span><br/>
boolean是否为true:<span th:text="${#bools.isTrue(boolean)}"></span><br/>
arrays的长度:<span th:text="${#arrays.length(array)}"></span><br/>
arrays是否包含张三:<span th:text="${#arrays.contains(array,'张三')}"></span><br/>
List是否为空:<span th:text="${#lists.isEmpty(list)}"></span><br/>
List的长度:<span th:text="${#lists.size(list)}"></span><br/>
Set是否为空:<span th:text="${#sets.isEmpty(set)}"></span><br/>
Set的长度:<span th:text="${#sets.size(set)}"></span><br/>
Map是否为空:<span th:text="${#maps.isEmpty(map)}"></span><br/>
Map的长度:<span th:text="${#maps.size(map)}"></span><br/>

前面很多代码都手动写了,后面例子都是直接复制的,因为语法差不多是一样的,如果不知道再来这看就是了。

以上代码笔记内容来自付费专栏:案例上手 Spring 全家桶

PS:如果侵犯版权,请联系我。

本文由老郭种树原创,转载请注明:https://guozh.net/spring-boot-thymeleaf-in-action/

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注