1、Thymeleaf简介
Thymeleaf is a modern server-side Java template engine for both web and standalone environments.
Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎。
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的html文档。从字面上理解模板引擎,最重要的就是模板二字,这个意思就是做好一个模板后套入对应位置的数据,最终以html的格式展示出来,这就是模板引擎的作用。
这里通过一个例子,演示如何使用Thymeleaf模板引擎。
2、前期准备:通过Mybatis访问数据库
这里对于数据的访问,复用了前面一篇例子中的MyBatis的部分代码,为了保证这篇的独立性,这里将前面的步骤附在如下。这部分主要是展示如何通过Mybatis访问数据库中的数据。
2.1依赖配置添加
在connnect/pom.xml
文件中添加mybatis依赖,如下:
4.0.0
com.space.mysql
connnect
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
8.0.11
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.0
2.2 添加在应用配置文件中添加MyBatis相关配置
主要是说明下数据库记录映射的类和mapper配置文件的路径信息。
application.properties
:
spring.datasource.username=root
spring.datasource.password=lfqylfqy
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#mybatis相关配置
#数据库记录映射类所在的包和mapper文件存放的位置
mybatis.type-aliases-package=com.space.mysql.connect.domain
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
新增一个mapper文件,并在其中定义相关的sql语句。
mybatis/mapper/StudentMapper.xml
:
insert into Student(id, name, age) VALUES (#{id}, #{name}, #{age})
update Student set name = #{name}, age = #{age} where id = #{id}
delete from Student where id = #{id}
2.3 Java代码编写
2.3.1 新增一个和数据库表中记录对应的java类
这里借用之前的表结构:
$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 51
Server version: 8.0.20 MySQL Community Server - GPL
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use testdb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> describe student;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(30) | YES | | NULL | |
| age | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql>
com.space.mysql.connect.domain.Student
:
package com.space.mysql.connect.domain;
/**
* Created by chengxia on 2021/12/11.
*/
public class Student {
private int id;
private String name;
private int age;
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.3.2 新增一个Mapper接口对应mapper配置文件
这个接口可以结合配置文件,对应到sql语句。
com.space.mysql.connect.mapper.StudentMapper
:
package com.space.mysql.connect.mapper;
import com.space.mysql.connect.domain.Student;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* Created by chengxia on 2021/12/11.
*/
@Mapper
public interface StudentMapper {
List queryStudentById(int id);
List queryStudentList();
void addStudent(Student stu);
void updateStudent(Student stu);
void deleteStudent(int id);
}
2.3.3 新增数据库Service类对数据库操作进行包装(调用mapper)
这里将服务多抽象了一层接口。
服务接口类com.space.mysql.connect.service.StudentServiceInterface
:
package com.space.mysql.connect.service;
import com.space.mysql.connect.domain.Student;
import java.util.List;
/**
* Created by chengxia on 2021/12/12.
*/
public interface StudentServiceInterface {
Student queryStudentById(int id);
List queryStudentList();
void addStudent(Student stu);
void updateStudent(Student stu);
void deleteStudent(int id);
}
服务实现类com.space.mysql.connect.service.StudentService
:
package com.space.mysql.connect.service;
import com.space.mysql.connect.domain.Student;
import com.space.mysql.connect.mapper.StudentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by chengxia on 2021/12/12.
*/
@Service
public class StudentService implements StudentServiceInterface {
@Autowired
private StudentMapper stuMapper;
@Override
public Student queryStudentById(int id) {
List studentList = stuMapper.queryStudentById(id);
if(studentList != null && studentList.size() > 0) {
System.out.println(studentList.get(0));
return studentList.get(0);
}else{
return null;
}
}
@Override
public List queryStudentList() {
List studentList = stuMapper.queryStudentList();
for (Student stu: studentList){
System.out.println(stu);
}
return studentList;
}
@Override
public void addStudent(Student stu) {
stuMapper.addStudent(new Student(stu.getId(), stu.getName(), stu.getAge()));
}
@Override
public void updateStudent(Student stu) {
stuMapper.updateStudent(new Student(stu.getId(),stu.getName(), stu.getAge()));
}
@Override
public void deleteStudent(int id) {
stuMapper.deleteStudent(id);
}
}
2.3.4 应用启动类中增加mapper等类的扫描包路径
这一步必不可少,不然会报错mapper类的bean找不到。
Consider defining a bean of type 'com.space.mysql.connect.mapper.StudentMapper' in your configuration.
com.space.mysql.connect.main.Application
:
package com.space.mysql.connect.main;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* Created by chengxia on 2021/12/7.
*/
@SpringBootApplication
@ComponentScan(basePackages = {"com.space.mysql.connect.controller","com.space.mysql.connect.service"})
@MapperScan(value = "com.space.mysql.connect.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
到这里,访问数据库相关的代码就完成了。
3、Thymeleaf模板的使用
3.1 依赖配置
connnect/pom.xml
文件中添加Thymeleaf相关的依赖配置:
4.0.0
com.space.mysql
connnect
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
8.0.11
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.0
org.thymeleaf
thymeleaf-spring5
org.thymeleaf.extras
thymeleaf-extras-java8time
3.2 新建一个使用Thymeleaf模板的Controller
这里单独写一个Controller用来调用Thymeleaf显示页面。
com.space.mysql.connect.controller.ThymeleafTemplateController
:
package com.space.mysql.connect.controller;
import com.space.mysql.connect.domain.Student;
import com.space.mysql.connect.service.StudentServiceInterface;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
/**
* Created by chengxia on 2021/12/12.
* 这里需要尤为注意,Controller注解 ,必须用Controller,不能用原来的RestController!
*/
@Controller
@RequestMapping("/student")
public class ThymeleafTemplateController {
@Autowired
private StudentServiceInterface stuService;
@RequestMapping("/queryList")
public String queryStudentList(ModelMap map){
map.addAttribute("student", stuService.queryStudentList());
return "StudentsList";
}
@RequestMapping("/delete")
public String deleteStudent(@RequestParam() int id, ModelMap map){
stuService.deleteStudent(id);
map.addAttribute("student", stuService.queryStudentList());
return "StudentsList";
}
@RequestMapping("/edit")
public String editStudent(ModelMap map, @RequestParam(defaultValue = "0") int id){
if(id > 0){
//该记录已经存在,就进行更新操作,查询详情并传入map
map.addAttribute("student", stuService.queryStudentById(id));
}else{
//新增一条记录
map.addAttribute("student",new Student(0,"TmpName", 9));
}
return "StudentEdit";
}
@RequestMapping(value = "/save", method = {RequestMethod.GET, RequestMethod.POST})
public String save(ModelMap map, @ModelAttribute Student student){
if(student == null){
return "Error Happened when add null...";
}
Student stuTmp= stuService.queryStudentById(student.getId());
if(stuTmp == null){
//如果没有查到记录,就新增
stuService.addStudent(student);
}else{
stuService.updateStudent(student);
}
map.addAttribute("student", stuService.queryStudentList());
return "StudentsList";
}
}
3.3 新建模板文件
3.3.1 原理简介
Spring Boot提供了大量模板引擎, 包含括FreeMarker、Groovy、 Thymeleaf、 Velocity和Mustache, Spring Boot中推荐
使用Thymeleaf作为模板引擎, 因为Thymeleaf提供了完美的Spring MVC的支持。
原理上说,Thymeleaf在Spring Boot的org.springframework.boot.autoconfigure.thymeleaf包下实现自动配置,如下所示:
ThymeleafAutoConfiguration源码:
@Configuration
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration {
//配置TemplateResolver
@Configuration
@ConditionalOnMissingBean(name = "defaultTemplateResolver")
static class DefaultTemplateResolverConfiguration {
...
}
//配置TemplateEngine
@Configuration
protected static class ThymeleafDefaultConfiguration {
...
}
//配置SpringWebFluxTemplateEngine
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
static class ThymeleafWebMvcConfiguration {
...
}
//配置thymeleafViewResolver
@Configuration
@ConditionalOnWebApplication(type = Type.REACTIVE)
@ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
static class ThymeleafWebFluxConfiguration {
...
}
...
}
ThymeleafAutoConfiguration自动加载Web所需的TemplateResolver、TemplateEngine、SpringWebFluxTemplateEngine以及thymeleafViewResolver,并通过ThymeleafProperties进行Thymeleaf属性配置。详细细节查看官方源码。
ThymeleafProperties源码:
//读取application.properties配置文件的属性
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
/**
*Web模板文件前缀路径属性,Spring boot默认路径为classpath:/templates/
*/
private String prefix = DEFAULT_PREFIX;
/**
* Web模板文件后缀属性,默认为html
*/
private String suffix = DEFAULT_SUFFIX;
/**
* Web模板模式属性,默认为HTML
*/
private String mode = "HTML";
/**
* Web模板文件编码属性,默认为UTF_8
*/
private Charset encoding = DEFAULT_ENCODING;
....
}
从上面如下部分的代码:
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
可以从ThymeleafProperties中看出,Thymeleaf的默认设置,以及可以通过前缀为spring.thymeleaf属性修改Thymeleaf默认配置。默认地,模板文件的后缀是“.html”放在templates目录下。
3.3.2 新建显示和修改信息的模板文件
显示信息列表的模板文件。
templates/StudentsList.html
:
Student List
New Student
ID
Name
Age
Edit
Delete
修改信息的模板。
templates/StudentEdit.html
:
Student Edit or New
到这里,代码全部完成了,目录结构如下:
4、运行效果
启动应用之后:
http://localhost:8080/student/queryList
:
点击上面的
Delete
,跳转到链接http://localhost:8080/student/delete?id=0
:
点击上面的
Edit
,跳转到链接http://localhost:8080/student/edit?id=2
:
将上面的年龄改成999:
点击
Submit
,跳转到http://localhost:8080/student/save
:
点击上面的
New Student
,跳转到http://localhost:8080/student/edit
:
修改信息如下:
点击
Submit
,跳转到http://localhost:8080/student/save
:
到这里示例就结束了。
参考资料
- Thymeleaf一篇就够了
- 【SpringBoot2.x】-SpringBoot Web开发中Thymeleaf、Web、Tomcat以及Favicon