1,简介
Thymeleaf是用于Web和独立环境的服务器端Java模板引擎。它能够处理HTML、XML、JavaScript、CSS甚至纯文本。
Thymeleaf的主要目标是提供一种简洁的,具有更好可维护性的创建模板的方法。为了实现这一点,它基于自然的模板概念,在不影响被当做设计原型的模板的前提下,将它的逻辑注入到模板文件中。这样既改善了设计上的沟通,也弥合了设计与开发团队间的分歧。
Thymeleaf从一开始设计时就考虑到了Web标准--尤其是HTML5--如果需要的话,可以创建完全校验的模板。
Thymeleaf可以处理6种模板,每种模板都称为模板模式:
HTML,XML,TEXT,JAVASCRIPT,CSS,RAW。
有两种标记模板模式(HTML和XML),三种文本模板模式(TEXT,JAVASCRIPT和CSS)和一种无操作模板模式(RAW),每种类型都被称为一种模板模式。
- HTML模板模式可以是任何类型的HTML,包括HTML5,HTML4和XHTML。这种模式不会做内容验证或格式检查,并且模板代码/结构在输出时尽可能保持原样。
- XML模板模式允许XML格式的输入。这样,代码格式必须是完整的--不允许未闭标签和未加引号的属性,如果格式错误,解析器会抛出异常。注意,不会对DTD或XML Schema验证。
- TEXT模板模式可对非标记性质的模板使用特殊语法。例如,文本电子邮件或模板化文档。注意,HTML或XML模板也可作为TEXT处理,在这种情况下,它们不会被解析为标记,而每个tag,DOCTYPE,注释等都被视为纯文本。
- JAVASCRIPT模板模式允许处理Thymeleaf应用程序中的JS文件。这意味着能像在HTML文件中那样在JS文件中使用模型数据,但要使用JS特有的集成方式,比如特殊转义(specialized escaping)或自然脚本(natural scripting)。JAVASCRIPT模板模式被看成是文本模式,因此使用与文本模板模式相同的特定语法。
- CSS模板模式允许处理Thymeleaf应用程序中涉及的CSS文件。类似于JAVASCRIPT模式,CSS模板模式也是文本模式,并使用TEXT模板模式中的特殊处理语法。
- RAW模板模式根本不会处理模板。它的作用是将未处理的资源(文件、URL响应等)插入正在处理的模板中。例如,可将HTML格式外部的、不受控制的资源包含到应用程序模板中,并且尽可能地让这些资源包含的任何Thymeleaf代码都不会被执行。
Thymeleaf是一个极具扩展性的模板引擎(实际上,它可以被称为模板引擎框架),它允许定义和定制模板处理的方式,以使其细节更加完善。
把某些逻辑用来标记工件(标记、文本、注释或占位符)的对象称为处理器,而一组这样的处理器(可能还有一些额外的工件)通常由方言组成(方言是指包含以th开头的属性,如<span th:text="...">)。Thymeleaf的核心库开箱即用地提供了一种称为标准方言的方言,对大多数用户来说这就足够了。
注意,方言实际上可以没有处理器,并且完全由其它类型的工件组成,但是处理器绝对是最常见的用例。
当然,如果想在利用库的高级特性的同时,定义自己的处理逻辑,那么,可以创建自己的方言(甚至扩展标准方言)。Thymeleaf还可以配置为一次使用几种方言。
标准方言的大多数处理器是属性处理器。这允许浏览器在处理HTML模板文件之前就正确地显示它们,因为它们会忽略额外的属性。例如,虽然使用标记库的JSP可能包含一些代码片段,但浏览器不能直接显示这些代码片段,比如:
<form:inputText name="userName" value="${user.name}" />
用标准方言实现相同的功能。
<input type="text" name="userName" value="James Carrot" th:value="${user.name}" />
这段代码不仅可以准确显示,而且还可以指定一个属性值(本例为James Carrot),当在浏览器中静态打开,这个属性值就能显示出来。而这将在处理模板时,由${user.name}的值替代。
2,示例
2.1,pom-引入thymeleaf
直接使用了webjars。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 前端资源 webjars begin -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>0.34</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.1.3</version>
</dependency>
<!-- 前端资源 webjars end -->
pom的完整内容在后面。
2.2,建立index.html文件
在resources/templates下,创建index.html。
thymeleaf模板页面默认放在/templates下。如无特殊说明,所有html都在这里。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/4.1.3/css/bootstrap.min.css">
<title>主页</title>
</head>
<body>
<div class="container">
<h2>来自Thymeleaf模板的内容</h2>
<h3>Hello Thymeleaf~</h3>
<h3>Location: templates/index.html</h3>
</div>
</body>
</html>
2.3,创建controller
不加任何内容的controller,访问index。
package com.thm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomeController {
@RequestMapping("/index")
public String index() {
return "index";
}
}
2.4,application文件
也可不加,基本都是默认配置。
# 可改变模板文件的位置
#spring.thymeleaf.prefix=/WEB-INF/page/
spring.thymeleaf.encoding=UTF-8
# 开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
2.5,主程序
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ThymeApplication {
public static void main(String[] args) {
SpringApplication.run(ThymeApplication.class, args);
}
}
运行,访问http://localhost:8080/,看下效果。
2.6,创建新index.html文件
在main里创建目录webapp/WEB-INF/page,创建文件index.html。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/4.1.3/css/bootstrap.min.css">
<title>index</title>
</head>
<body>
<div class="container">
<h2>Thymeleaf首页</h2>
<h3>这是个例子</h3>
<h3>Location: webapp/WEB-INF/page/index.html</h3>
</div>
</body>
</html>
2.7,更改模板位置
# 改变模板文件的位置
spring.thymeleaf.prefix=/WEB-INF/page/
运行,访问http://localhost:8080/index,对比变化的地方。
可见到访问的位置已经发生了变化。
2.8,创建show.html
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="all"
href="/webjars/bootstrap/4.1.3/css/bootstrap.min.css">
<script type="text/javascript" src="/webjars/jquery/3.3.1/jquery.min.js/"></script>
<script type="text/javascript" src="/webjars/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<title>多语言内容</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4">
<div class="panel panel-primary">
<div class="panel-heading text-center">
<span class="panel-title card text-white bg-primary mb-1">个人信息</span>
</div>
<div class="panel-body card text-white bg-secondary mb-3">
编号:<span th:text="#{student.id}" class="card text-white bg-success mb-1">3</span><br />
姓名:<span th:text="#{student.name}" class="card text-white bg-success mb-1">这是姓名</span><br />
性别:<span th:text="#{student.gender}" class="card text-white bg-success mb-1">男</span><br />
年龄:<span th:text="#{student.age}" class="card text-white bg-success mb-1">22</span><br />
电话:<span th:text="#{student.phone}" class="card text-white bg-success mb-1">15812341111</span><br />
</div>
</div>
</div>
</div>
</div>
</body>
</html>
其中的显示的字段会被资源文件中的字符串替换掉。
2.9,创建资源文件
多语言资源文件默认放在/static/下,可在这里建独立目录i18n,放以特定文件名开头的不同语言的文件。
1、中文,messages_zh_CN.properties,需要用unicode编码,通过native2ascii a.txt转换出来。
student.id=1
student.name=\u4f4f\u5bbf\u8d39
student.gender=\u5e74\u6ee1
student.age=882
student.phone=13111112222
2、英文,默认的,messages.properties,不需要转换
student.id=1
student.name=住宿费
student.gender=年满
student.age=882
student.phone=13111112222
3、修改application.properties,设置资源文件位置
spring.messages.basename=static/i18n/messages
#缓存刷新时间
spring.messages.cache-seconds=2
spring.messages.encoding=UTF-8
2.10,更新controller
加上新的映射。
@RequestMapping("/sst")
public String showStudent() {
return "show";
}
运行,看看效果,http://localhost:8080/show。
2.11,创建model
访问数据库,用mongodb。数据库-test,用户名/密码-test/test,表名(集合)是userInfo。
@Document(collection = "userInfo")
public class User implements Serializable {
private static final long serialVersionUID = -1L;
@Id
private String id;
private long uid;
private String userName;
private String userAddr;
public User() {
super();
}
public User(Integer uid, String userName, String userAddr) {
super();
this.uid = uid;
this.userName = userName;
this.userAddr = userAddr;
}
public User(String id, Integer uid, String userName, String userAddr) {
super();
this.id = id;
this.uid = uid;
this.userName = userName;
this.userAddr = userAddr;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAddr() {
return userAddr;
}
public void setUserAddr(String userAddr) {
this.userAddr = userAddr;
}
@Override
public String toString() {
return "User [id=" + id + ", uid=" + uid + ", userName=" + userName + ", userAddr=" + userAddr + "]";
}
}
2.12,创建dao
package com.thm.dao;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.thm.model.User;
public interface UserRepository extends MongoRepository<User, String> {
User findByUserName(String userName);
List<User> findByUserNameStartingWith(String prefix);
List<User> findByUserNameEndingWith(String suffix);
void deleteByUid(long uid);
}
2.13,创建service
package com.thm.service;
import java.util.List;
import com.thm.model.User;
public interface UserService {
void save(User user);
void delByUid(long uid);
void delById(String id);
void update(User user);
User findByUserName(String userName);
List<User> findByNameStartingWith(String prefix);
List<User> findByNameEndingWith(String suffix);
List<User> findList();
User findById(String id);
}
package com.thm.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.thm.dao.UserRepository;
import com.thm.model.User;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepo;
@Override
public void save(User user) {
userRepo.save(user);
}
@Override
public User findByUserName(String userName) {
return userRepo.findByUserName(userName);
}
@Override
public List<User> findByNameStartingWith(String prefix) {
return userRepo.findByUserNameStartingWith(prefix);
}
@Override
public List<User> findByNameEndingWith(String suffix) {
return userRepo.findByUserNameEndingWith(suffix);
}
@Override
public List<User> findList() {
return userRepo.findAll();
}
@Override
public User findById(String id) {
Optional<User> opUser = userRepo.findById(id);
return opUser.orElse(null);
}
@Override
public void update(User user) {
userRepo.save(user);
}
@Override
public void delByUid(long uid) {
userRepo.deleteByUid(uid);
}
@Override
public void delById(String id) {
userRepo.deleteById(id);
}
}
图省事,写一起了。这一层也可以去掉,直接用dao。
2.14,创建controller
package com.thm.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.thm.model.User;
import com.thm.service.UserService;
@Controller
@RequestMapping(value = "/user")
public class UserController {
@Autowired
private UserService userService;
private static final String RET_USER = "redirect:/user/";
@RequestMapping(method = RequestMethod.GET)
public String getUserList(ModelMap map) {
map.addAttribute("users", userService.findList());
return "userList";
}
// 显示创建用户的表单
@RequestMapping(value = "/create", method = RequestMethod.GET)
public String createUser(ModelMap map) {
map.addAttribute("user", new User());
map.addAttribute("action", "create");
return "userForm";
}
/**
* 创建用户
* 处理"/user"的POST请求,用来获取用户列表
* 通过@ModelAttribute绑定参数,也通过@RequestParam从页面中传递参数
*/
@RequestMapping(value = "/create", method = RequestMethod.POST)
public String postUser(@ModelAttribute User user) {
userService.save(user);
return RET_USER;
}
/**
* 更新用户表单
* 处理"/user/{id}"的GET请求,通过URL中的id值获取User信息
*/
@RequestMapping(value = "/update/{id}", method = RequestMethod.GET)
public String getUser(@PathVariable(name = "id") String id, ModelMap map) {
map.addAttribute("user", userService.findById(id));
map.addAttribute("action", "update");
return "userForm";
}
/**
* 处理"/user/{id}"的PUT请求,更新User
*/
@RequestMapping(value = "/update", method = RequestMethod.POST)
public String putUser(@ModelAttribute User user) {
userService.update(user);
return RET_USER;
}
/**
* 处理"/user/{uid}"的GET请求,删除User
*/
@RequestMapping(value = "/deletebyuid/{uid}", method = RequestMethod.GET)
public String deleteUser(@PathVariable(name = "uid") long uid) {
userService.delByUid(uid);
return RET_USER;
}
@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
public String deleteUser(@PathVariable(name = "id") String id) {
userService.delById(id);
return RET_USER;
}
}
更新application.properties
# 数据库连接
spring.data.mongodb.uri=mongodb://test:test@localhost:27017/test
2.15,创建新模板文件
1,新增userform.html
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="all"
href="/webjars/bootstrap/4.1.3/css/bootstrap.min.css">
<script type="text/javascript" src="/webjars/jquery/3.3.1/jquery.min.js/"></script>
<script type="text/javascript" src="/webjars/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<title>userForm</title>
</head>
<body>
<div class="container">
<legend>
<strong>用户信息</strong>
</legend>
<form th:action="@{/user/{action}(action=${action})}" method="post" class="card bg-light">
<div class="form-group">
<label for="id" class="col-sm-2 control-label">ID</label>
<div class="col-xs-4">
<input type="text" class="form-control" id="id" name="id" th:value="${user.id}" />
</div>
</div>
<div class="form-group">
<label for="uid" class="col-sm-2 control-label">编号</label>
<div class="col-xs-4">
<input type="text" class="form-control" id="uid" name="uid"
th:value="${user.uid}" />
</div>
</div>
<div class="form-group">
<label for="userName" class="col-sm-2 control-label">名称</label>
<div class="col-xs-4">
<input type="text" class="form-control" id="userName" name="userName"
th:value="${user.userName}" />
</div>
</div>
<div class="form-group">
<label for="userAddr" class="col-sm-2 control-label">地址</label>
<div class="col-xs-4">
<input type="text" class="form-control" id="userAddr" name="userAddr"
th:value="${user.userAddr}" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input class="btn btn-primary" type="submit" value="提交" /> <input
class="btn btn-secondary" type="button" value="返回" onclick="history.back()" />
</div>
</div>
</form>
</div>
</body>
</html>
2,列表userlist.html
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="all"
href="/webjars/bootstrap/4.1.3/css/bootstrap.min.css">
<script type="text/javascript" src="/webjars/jquery/3.3.1/jquery.min.js/"></script>
<script type="text/javascript" src="/webjars/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<title>userList</title>
</head>
<body>
<div class="container">
<table class="table table-bordered table-hover alert alert-success ">
<legend>
<strong>用户列表</strong>
</legend>
<thead>
<tr>
<th>ID</th>
<th>编号</th>
<th>名称</th>
<th>地址</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<th scope="row"><a th:href="@{/user/update/{id}(id=${user.id})}"
th:text="${user.id}"></a></th>
<td th:text="${user.uid}"></td>
<td th:text="${user.userName}"></td>
<td th:text="${user.userAddr}"></td>
<td><a class="btn btn-success" th:href="@{/user/create}">新增</a> <a
class="btn btn-danger" th:href="@{/user/deletebyuid/{uid}(uid=${user.uid})}">删除</a></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
2.16,更新pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
运行,http://localhost:8080/user
<?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.sitech.billing.biop</groupId>
<artifactId>webt</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>Thymeleaf Exam</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud-task.version>2.0.0.RELEASE</spring-cloud-task.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 前端资源 webjars begin -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>0.34</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.1.3</version>
</dependency>
<!-- 前端资源 webjars end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>