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/