一、使用idea新建web工程
1、引入Thymeleaf依赖
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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cobra.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>thymeleaf</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
<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>
3、工程结构为:
二、后端coding:
1、定义domain,User.java:
package com.cobra.thymeleaf.domain;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/23 22:34
*/
public class User {
private Integer userId;
private String username;
private String address;
private String email;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", username='" + username + '\'' +
", address='" + address + '\'' +
", email='" + email + '\'' +
'}';
}
}
2、service层
定义接口UserService和方法:
package com.cobra.thymeleaf.service;
import com.cobra.thymeleaf.domain.User;
import java.util.Collection;
/**
* @Author: Baron
* @Description: 用户服务接口
* @Date: Created in 2019/3/23 23:26
*/
public interface UserService {
/**
* 根据userId查找User
*
* @param userId
* @return
*/
User findById(Integer userId);
/**
* 添加新用户
*
* @param user
*/
void add(User user);
/**
* 查询所有用户
*
* @return
*/
Collection<User> findAllUsers();
}
实现接口方法,使用ConcurrentHashMap存储用户信息,AtomicInteger生成用户id:
package com.cobra.thymeleaf.service.impl;
import com.cobra.thymeleaf.domain.User;
import com.cobra.thymeleaf.service.UserService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author: Baron
* @Description: 用户服务实现
* @Date: Created in 2019/3/23 23:42
*/
@Service
public class UserServiceImpl implements UserService {
private ConcurrentMap<Integer, User> userMap = new ConcurrentHashMap<>();
private final static AtomicInteger idGenerator = new AtomicInteger();
/**
* 根据userId查找User
*
* @param userId
* @return
*/
@Override
public User findById(Integer userId) {
return userMap.get(userId);
}
/**
* 添加新用户
*
* @param user
*/
@Override
public void add(User user) {
user.setUserId(idGenerator.incrementAndGet());
userMap.put(user.getUserId(), user);
}
/**
* 查询所有用户
*
* @return
*/
@Override
public Collection<User> findAllUsers() {
return userMap.values();
}
}
3、controller层:
package com.cobra.thymeleaf.controller;
import com.cobra.thymeleaf.domain.User;
import com.cobra.thymeleaf.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Collection;
import java.util.Map;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/24 15:25
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 获取所有用户
* @param model
* @return
*/
@GetMapping("/list")
public String index(Model model) {
Collection<User> users = userService.findAllUsers();
model.addAttribute("users", users);
return "list";
}
/**
* 根据id获取单个用户详情
* @param userId
* @param model
* @return
*/
@GetMapping("/detail")
public String detail(@RequestParam Integer userId,Model model) {
User user = userService.findById(userId);
model.addAttribute("user", user);
return "detail";
}
/**
* 根据id获取单个用户详情
* @param userId
* @param model
* @return
*/
@GetMapping("/{userId}")
public String getDetail(@PathVariable("userId") Integer userId, Model model) {
User user = userService.findById(userId);
model.addAttribute("user", user);
return "detail";
}
/**
* 返回添加用户页
* @return
*/
@GetMapping("/add")
public String add() {
return "add";
}
/**
* 添加用户操作
* @param user
* @return
*/
@PostMapping("/save")
public String save(User user) {
userService.add(user);
return "redirect:/user/list";
}
}
三、前端视图模板的定义:
在resources下templates中定义模板,新建html文件(业务逻辑可以提前看第四部分测试):
1、用户list.html列表页:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>列表页</title>
</head>
<style>
td {
text-align: center;
height: 30px;
}
.code {
width: 40px
}
.username {
width: 80px
}
.address {
width: 150px
}
.link {
width: 130px
}
</style>
<body>
<h3>欢迎来到!</h3>
<a href="/user/add">添加新用户</a>
<br>
<br>
<table>
<thead>
<tr>
<td class="code">编号</td>
<td class="username">姓名</td>
<td class="address">地址</td>
<td class="link">详情(?userId=..)</td>
<td class="link">详情(Restful)</td>
</tr>
</thead>
<tbody>
<tr th:each="user:${users}">
<td class="code" scope="row" th:text="${user.userId}">1</td>
<td class="username" th:text="${user.username}">默认姓名</td>
<td class="address" th:text="${user.address}">默认地址</td>
<td class="link"><a th:href="@{../user/detail(userId=${user.userId})}" target="_blank">查看详情</a></td>
<td class="link"><a th:href="@{../user/{userId}(userId=${user.userId})}" target="_blank">查看详情</a></td>
</tr>
</tbody>
</table>
</body>
</html>
2、用户添加add.html页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新建用户</title>
</head>
<body>
<h3>新建用户</h3>
<form action="/user/save" method="post">
<label>姓名:</label><input type="text" name="username"/><br><br>
<label>地址:</label><input type="text" name="address"/><br><br>
<label>邮箱:</label><input type="text" name="email"/><br><br>
<input type="submit" value="提交"/>
</form>
</body>
</html>
3、用户详情detail页面:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>用户详情</title>
<style>
td {
height: 30px;
}
.left {
width: 50px;
}
.right {
width: 150px;
}
</style>
</head>
<body>
<h3>用户详情-获取方式一</h3>
<table>
<tr>
<td class="left">编号:</td>
<td class="right" th:text="${user.userId}">默认编号</td>
<tr>
<td>姓名:</td>
<td th:text="${user.username}">默认姓名</td>
<tr>
<td>地址:</td>
<td th:text="${user.address}">默认地址</td>
<tr>
<td>邮编:</td>
<td th:text="${user.email}">默认邮箱</td>
</table>
<h3>用户详情-获取方式二</h3>
<table th:object="${user}">
<tr>
<td class="left">编号:</td>
<td class="right" th:text="*{userId}">默认编号</td>
<tr>
<td>姓名:</td>
<td th:text="*{username}">默认姓名</td>
<tr>
<td>地址:</td>
<td th:text="*{address}">默认地址</td>
<tr>
<td>邮编:</td>
<td th:text="*{email}">默认邮箱</td>
</table>
</body>
</html>
四、测试Thymeleaf的模板引擎功能:
1、启动工程,访问http://localhost:8080/user/list:
2、添加用户:
3、提交返回:
4、查看详情:
五、页面静态化实现模板转化为html页面,可以让前端直接浏览html页面,减少对数据库的请求:
1、定义静态化服务接口StaticService 及将list.ftl生成index.html的方法:
package com.cobra.thymeleaf.service;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/24 18:11
*/
public interface StaticService {
/**
* 生成首页静态页面
*/
void createIndexHtml();
}
2、实现类:
package com.cobra.thymeleaf.service.impl;
import com.cobra.thymeleaf.service.StaticService;
import com.cobra.thymeleaf.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import java.io.*;
import java.net.URISyntaxException;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/24 18:12
*/
@Service
public class StaticServiceImpl implements StaticService {
@Autowired
private UserService userService;
/**
* 生成首页静态页面
*/
@Override
public void createIndexHtml() {
try {
ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
resolver.setPrefix("templates/");
resolver.setSuffix(".html");
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(resolver);
Context context = new Context();
context.setVariable("users", userService.findAllUsers());
/**获取输出目标文件输出流------开始*/
String filepath = this.getClass().getResource("/").toURI().getPath() + "static/";
File folder = new File(filepath);
//如果文件夹不存在
if (!folder.exists()) {
folder.mkdir();
}
String indexFileName = "index.html";
File indexHtml = new File(folder, indexFileName);
//如果html文件不存在
if (!indexHtml.exists()) {
indexHtml.createNewFile();
}
Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(indexHtml), "UTF-8"));
/**获取输出目标文件输出流------结束*/
templateEngine.process("list", context, writer);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
3、在UserController中,添加用户时,调用静态方法,实现每次添加用户,都会生成最新的静态页面,如果有修改、删除操作,也要调用静态化方法:
package com.cobra.thymeleaf.controller;
import com.cobra.thymeleaf.domain.User;
import com.cobra.thymeleaf.service.StaticService;
import com.cobra.thymeleaf.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/24 15:25
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private StaticService staticService;
/**
* 获取所有用户
* @param model
* @return
*/
@GetMapping("/list")
public String index(Model model) {
Collection<User> users = userService.findAllUsers();
model.addAttribute("users", users);
return "list";
}
/**
* 根据id获取单个用户详情
* @param userId
* @param model
* @return
*/
@GetMapping("/detail")
public String detail(@RequestParam Integer userId,Model model) {
User user = userService.findById(userId);
model.addAttribute("user", user);
return "detail";
}
/**
* 根据id获取单个用户详情
* @param userId
* @param model
* @return
*/
@GetMapping("/{userId}")
public String getDetail(@PathVariable("userId") Integer userId, Model model) {
User user = userService.findById(userId);
model.addAttribute("user", user);
return "detail";
}
/**
* 返回添加用户页
* @return
*/
@GetMapping("/add")
public String add() {
return "add";
}
/**
* 添加用户操作
* @param user
* @return
*/
@PostMapping("/save")
public String save(User user) {
System.out.println(user);
userService.add(user);
staticService.createIndexHtml();
return "redirect:/user/list";
}
}
4、为了防止报错java.lang.ClassNotFoundException: ognl.PropertyAccessor,需要加依赖包
参考https://blog.youkuaiyun.com/lookbbs/article/details/85276615,特别鸣谢!
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.1.12</version>
</dependency>
5、添加一个用户之后,在static下会生成一个index.html页面:
直接访问生成的html页面:http://localhost:8080/index.html:
六、项目下载地址:https://github.com/yaobaron/thymeleafdemo