目录
1. SpringBoot 数据访问
1.1 Spring Boot 整合 MyBatis
1.1.1 基础环境搭建
1.1.2 注解方式整合 Mybatis
1.1.3 配置文件的方式整合 MyBatis
1.2 Spring Boot 整合 Redis
2. SpringBoot 视图技术
2.1 支持的视图技术
2.2 Thymeleaf
2.2.1 Thymeleaf 语法
2.2.2 基本使用
2.2.3 完成数据的页面展示
3. SpringBoot 实战演练
4. Spring Boot 项目部署
MyBatis 是一款优秀的持久层框架,Spring Boot 官方虽然没有对 MyBatis 进行整合,但是 MyBatis 团队自行适配了对应的启动器,进一步简化了使用 MyBatis 进行数据的操作。
因为 Spring Boot 框架开发的便利性,所以实现 Spring Boot 与数据访问层框架(例如 MyBatis)的整合非常简单,主要是引入对应的依赖启动器,并进行数据库相关参数设置即可。
(1). 数据准备
在 MySQL 中,先创建了一个数据库 springbootdata,然后创建了两个表 t_article 和 t_comment 并向表中插入数据。其中评论表 t_comment 的 a_id 与文章表 t_article 的主键 id 相关联。
# 创建数据库
CREATE DATABASE IF NOT EXISTS springbootdata DEFAULT CHARACTER SET utf8;
# 选择使用数据库
USE springbootdata;
# 创建表 t_article 并插入相关数据
DROP TABLE IF EXISTS t_article;
CREATE TABLE t_article
(
id int(20) NOT NULL AUTO_INCREMENT COMMENT '文章id',
title varchar(200) DEFAULT NULL COMMENT '文章标题',
content longtext COMMENT '文章内容',
PRIMARY KEY (id)
) ENGINE = InnoDB AUTO_INCREMENT = 2 DEFAULT CHARSET=utf8;
INSERT INTO t_article VALUES (1, 'Spring Boot 基础入门', '从入门到精通讲解...');
INSERT INTO t_article VALUES (2, 'Spring Cloud 基础入门', '从入门到精通讲解...');
# 创建表 t_comment 并插入相关数据
DROP TABLE IF EXISTS t_comment;
CREATE TABLE t_comment
(
id int(20) NOT NULL AUTO_INCREMENT COMMENT '评论id',
content longtext COMMENT '评论内容',
author varchar(200) DEFAULT NULL COMMENT '评论作者',
a_id int(20) DEFAULT NULL COMMENT '关联的文章id',
PRIMARY KEY (id)
) ENGINE = InnoDB AUTO_INCREMENT = 3 DEFAULT CHARSET=utf8;
INSERT INTO t_comment VALUES (1, '很全、很详细', 'lucy', 1);
INSERT INTO t_comment VALUES (2, '赞一个', 'tom', 1);
INSERT INTO t_comment VALUES (3, '很详细', 'eric', 1);
INSERT INTO t_comment VALUES (4, '很好,非常详细', '张三', 1);
INSERT INTO t_comment VALUES (5, '很不错', '李四', 2);
(2). 创建项目,引入相应的启动器
使用 Spring Initializr 来初始化项目。
项目名:springbootmybatis
包名:com.zm
启动器:SQL 的 MyBatis Framework、MySQL Driver,Web 的 Spring Web
(3). 编写与数据库表 t_comment 和 t_article 对应的实体类 Comment 和 Article
com.zm.pojo.Comment
public class Comment {
private Integer id;
private String content;
private String author;
private Integer aId;
// getter setter toString ...
}
com.zm.pojo.Article
public class Article {
private Integer id;
private String title;
private String content;
// getter setter toString ...
}
(4). 编写配置文件
application.properties 更名为 application.yml。在 application.properties 配置文件中进行数据库连接配置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: password
需求:实现通过 ID 查询 Comment 信息。
(1). 创建一个对 t_comment 表数据操作的接口 CommentMapper
com.zm.mapper.CommentMapper
public interface CommentMapper {
@Select("select * from t_comment where id = #{id}")
Comment findById(Integer id);
}
(2). 在 Spring Boot 项目启动类上添加 @MapperScan("xxx") 注解
com.zm.SpringbootmybatisApplication
@SpringBootApplication
@MapperScan("com.zm.mapper") //执行扫描mapper的包名
public class SpringbootmybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootmybatisApplication.class, args);
}
}
(3). 编写测试方法
导入 Junit 的依赖,增加测试方法:
com.zm.SpringbootmybatisApplicationTests
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringbootmybatisApplicationTests {
// @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
private CommentMapper commentMapper;
@Test
void findCommentById() {
Comment comment = commentMapper.findById(1);
System.out.println(comment);
}
}
控制台中查询的 Comment 的 aId 属性值为 null,没有映射成功。这是因为编写的实体类 Comment 中使用了驼峰命名方式将 t_comment 表中的 a_id 字段设计成了 aId 属性,所以无法正确映射查询结果。
为了解决上述由于驼峰命名方式造成的表字段值无法正确映射到类属性的情况,可以在 Spring Boot 全局配置文件 application.yml 中添加开启驼峰命名匹配映射配置,示例代码如下:
mybatis:
configuration:
# 开启驼峰命名匹配映射
map-underscore-to-camel-case: true
第一、二步骤使用 Free Mybatis plugin 插件生成:使用 IDEA 连接 Database,然后选中要自动生成代码的表,右键 -> mybatis-generator -> 按照需求输入信息,点击 ok。
(1). 创建一个用于对数据库表 t_article 数据操作的接口 ArticleMapper
public interface ArticleMapper {
int deleteByPrimaryKey(Integer id);
int insert(Article record);
int insertSelective(Article record);
Article selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(Article record);
int updateByPrimaryKey(Article record);
}
(2). 创建 XML 映射文件
resources 目录下创建一个统一管理映射文件的包 mapper,并在该包下编写与 ArticleMapper 接口方应的映射文件 ArticleMapper.xml
id, title, content
delete from t_article
where id = #{id,jdbcType=INTEGER}
insert into t_article (title, content)
values (#{title,jdbcType=VARCHAR}, #{content,jdbcType=VARCHAR})
insert into t_article
title,
content,
#{title,jdbcType=VARCHAR},
#{content,jdbcType=VARCHAR},
update t_article
title = #{title,jdbcType=VARCHAR},
content = #{content,jdbcType=VARCHAR},
where id = #{id,jdbcType=INTEGER}
update t_article
set title = #{title,jdbcType=VARCHAR},
content = #{content,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
(3). 配置 XML 映射文件路径
在项目中编写的 XML 映射文件,Spring Boot 并无从知晓,所以无法扫描到该自定义编写的 XML 配置文件,还必须在全局配置文件 application.yml 中添加 MyBatis 映射文件路径的配置,同时需要添加实体类别名映射路径,示例代码如下:
mybatis:
configuration:
# 开启驼峰命名匹配映射
map-underscore-to-camel-case: true
# 加载 resources/mapper 文件夹下的所有的 xml 文件
mapper-locations: classpath:mapper/*.xml
# 配置 XML 映射文件中指定的实体类别名路径
type-aliases-package: com.zm.pojo
(4). 编写单元测试进行接口方法测试
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringbootmybatisApplicationTests {
@Autowired
private ArticleMapper articleMapper;
@Test
void findArticleById() {
Article article = articleMapper.selectByPrimaryKey(1);
System.out.println(article);
}
}
(1). 添加Redis依赖包
在项目的 pom.xml 中添加如下:
org.springframework.boot
spring-boot-starter-data-redis
(2). 配置 Redis 数据库连接
在 application.yml 中配置redis数据库连接信息,如下:
spring:
redis:
# Redis 服务器地址
host: 192.168.186.128
# Redis 服务器连接端口
port: 6379
jedis:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 18
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: 3000
# 连接池中的最大空闲连接
max-idle: 20
# 连接池中的最小空闲连接
min-idle: 2
# 连接超时时间(毫秒)
timeout: 3000
# Redis 数据库索引(默认为 0)
database: 0
(3). 编写 Redis 操作工具类
将 RedisTemplate 实例包装成一个工具类,便于对 redis 进行数据操作。
package com.zm.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @author ZM
* @since 2021-10-30 1:00
*/
@Component
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
/**
* 读取缓存
*/
public Object get(final String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 写入缓存
*/
public boolean set(String key, Object value) {
boolean result = false;
try {
redisTemplate.opsForValue().set(key, value, 1, TimeUnit.DAYS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 更新缓存
*/
public boolean getAndSet(final String key, String value) {
boolean result = false;
try {
redisTemplate.opsForValue().getAndSet(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 删除缓存
*/
public boolean delete(final String key) {
boolean result = false;
try {
redisTemplate.delete(key);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
(4). 测试
写一个测试用例类来完成对 redis 的整合。
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringbootmybatisApplicationTests {
// 写入,key:1,value:mysql 数据库中 id 为 1 的 article 记录
@Autowired
private RedisUtils redisUtils;
@Test
void writeRedis() {
redisUtils.set("1", articleMapper.selectByPrimaryKey(1));
System.out.println("success");
}
@Test
void readRedis() {
Article article = (Article) redisUtils.get("1");
System.out.println(article);
}
}
前端模板引擎技术的出现,使前端开发人员无需关注后端业务的具体实现,只关注自己页面的呈现效果即可,并且解决了前端代码错综复杂的问题、实现了前后端分离开发。Spring Boot 框架对很多常用的模板引擎技术(如:FreeMarker、Thymeleaf、Mustache 等)提供了整合支持。
Spring Boot 不太支持常用的 JSP 模板,并且没有提供对应的整合配置,这是因为使用嵌入式 Servlet 容器的 Spring Boot 应用程序对于 JSP 模板存在一些限制 :
Thymeleaf 是一种现代的基于服务器端的 Java 模板引擎技术,也是一个优秀的面向 Java 的 XML、XHTML、HTML5 页面模板,它具有丰富的标签语言、函数和表达式,在使用 Spring Boot 框架进行页面设计时,一般会选择 Thymeleaf 模板。
在 HTML 页面上使用 Thymeleaf 标签,Thymeleaf 标签能够动态地替换掉静态内容,使页面动态展示。
为了更直观的认识 Thymeleaf,下面展示一个在 HTML 文件中嵌入了 Thymeleaf 的页面文件,示例代码如下:
Title
欢迎进入Thymeleaf的学习
上述代码中,“xmlns:th="http://www.thymeleaf.org" 用于引入 Thymeleaf 模板引擎标签,使用关键字 th 标注标签是 Thymeleaf 模板提供的标签,其中,th:href="@{/css/gtvg.css}" 用于引入外联样式文件,th:text="${hello}" 用于动态显示标签文本内容。
常用标签:
标准表达式:
1. 变量表达式:${...}
变量表达式 ${...} 主要用于获取上下文中的变量值,示例代码如下:
这是标题
示例使用了 Thymeleaf 模板的变量表达式 ${...} 用来动态获取 P 标签中的内容,如果当前程序没有启动或者当前上下文中不存在 title 变量,该片段会显示标签默认值“这是标题”;如果当前上下文中存在 title 变量并且程序已经启动,当前 P 标签中的默认文本内容将会被 title 变量的值所替换,从而达到模板引擎页面数据动态替换的效果。
同时,Thymeleaf 为变量所在域提供了一些内置对象,具体如下所示:
#ctx:上下文对象
#vars:上下文变量
#locale:上下文区域设置
#request:(仅限 Web Context)HttpServletRequest 对象
#response:(仅限 Web Context)HttpServletResponse 对象
#session:(仅限 Web Context)HttpSession 对象
#servletContext:(仅限 Web Context)ServletContext 对象
结合上述内置对象的说明,假设要在 Thymeleaf 模板引擎页面中动态获取当前国家信息,可以使用 #locale 内置对象,示例代码如下:
The locale country is: China
上述代码中,使用 th:text="${#locale.country}" 动态获取当前用户所在国家信息,其中标签内默认内容为 China,程序启动后通过浏览器查看当前页面时,Thymeleaf 会通过浏览器语言设置来识别当前用户所在国家信息,从而实现动态替换。
2. 选择变量表达式:*{...}
选择变量表达式和变量表达式用法类似,一般用于从被选定对象而不是上下文中获取属性值,如果没有选定对象,则和变量表达式一样,示例代码如下:
titile: 标题.
*{title} 选择变量表达式获取当前指定对象 book 的 title 属性值。
3. 消息表达式:#{...}
消息表达式 #{...} 主要用于 Thymeleaf 模板页面国际化内容的动态替换和展示,使用消息表达式 #{...} 进行国际化设置时,还需要提供一些国际化配置文件。
4. 链接表达式 :@{...}
链接表达式 @{...} 一般用于页面跳转或者资源的引入,在 Web 开发中占据着非常重要的地位,并且使用也非常频繁,示例代码如下:
view
view
上述代码中,链接表达式 @{...} 分别编写了绝对链接地址和相对链接地址。在有参表达式中,需要按照 @{路径(参数名称=参数值,参数名称=参数值...)} 的形式编写,同时该参数的值可以使用变量表达式来传递动态参数值。
5. 片段表达式 :~{...}
片段表达式 ~{...} 用来标记一个片段模板,并根据需要移动或传递给其他模板。其中,最常见的用法是使用 th:insert 或 th:replace 属性插入片段,示例代码如下:
上述代码中,使用 th:insert 属性将 title 片段模板引用到该标签中。thymeleafDemo 为模板名称,Thymeleaf 会自动查找 /resources/templates/ 目录下的 thymeleafDemo 模板,title 为片段名称。
1) Thymeleaf 模板基本配置
首先在 Springbootdemo2 项目中使用 Thymeleaf 模板,首先必须保证引入 Thymeleaf 依赖,示例代码如下:
org.springframework.boot
spring-boot-starter-thymeleaf
其次,在全局配置文件中配置 Thymeleaf 模板的一些参数。一般 Web 项目都会使用下列配置,示例代码如:
spring:
thymeleaf:
# 在开发阶段,为了验证建议关闭缓存
cache: true
# 模板编码
encoding: UTF-8
# 应用于模板的模板模式
mode: HTML5
# 指定模板页面存放路径
prefix: classpath:/templates/
# 指定模板页面名称的后缀
suffix: .html
上述配置中,spring.thymeleaf.cache 表示是否开启 Thymeleaf 模板缓存,默认为 true,在开发过程中通常会关闭缓存,保证项目调试过程中数据能够及时响应;spring.thymeleaf.prefix 指定了 Thymeleaf 模板页面的存放路径,默认为classpath:/templates/;spring.thymeleaf.suffix 指定了 Thymeleaf 模板页面的名称后缀,默认为 .html。
2)静态资源的访问
开发 Web 应用时,难免需要使用静态资源。Spring boot 默认设置了静态资源的访问路径。
使用 Spring Initializr 方式创建的 Spring Boot 项目,默认生成了一个 resources 目录,在 resources 目录中的 public、resources、static 三个子目录下,Spring boot 默认会挨个从public、resources、static 里面查找静态资源。
1)创建 Spring Boot 项目,引入 Thymeleaf 依赖。
2)编写配置文件。
编辑 application.yml 全局配置文件,在该文件中对 Thymeleaf 模板页面的数据缓存进行设置。
# thymeleaf 页面缓存设置(默认为 true),开发中方便调试应设置为 false,上线稳定后应保持默认 true
spring:
thymeleaf:
cache: false
使用 spring.thymeleaf.cache=false 将 Thymeleaf 默认开启的缓存设置为了 false,用来关闭模板页面缓存。
3)创建 web 控制类
在项目中创建名为 com.zm.controller 的包,并在该包下创建一个用于前端模板页面动态数据替换效果测试的访问实体类 LoginController。
@Controller
public class LoginController {
@RequestMapping("/toLogin")
public String toLoginView(Model model){
model.addAttribute("currentYear", Calendar.getInstance().get(Calendar.YEAR));
return "login"; // resources/templates/login.html
}
}
toLoginView() 方法用于向登录页面 login.html 跳转,同时携带了当前年份信息 currentYear。
4)创建模板页面并引入静态资源文件。
在 classpath:/templates/ 目录下引入一个用户登录的模板页面 login.html。
用户登录界面
通过 xmlns:th="http://www.thymeleaf.org 引入了 Thymeleaf 模板标签;
使用 th:href 和 th:src 分别引入了两个外联的样式文件和一个图片;
使用 th:text 引入了后台动态传递过来的当前年份 currentYear。
5)效果测试
可以看出,登录页面 login.html 显示正常,在页面底部动态显示了当前日期 2020-2021,而不是文件中的静态数字 2019-2020。这进一步说明了 Spring Boot 与 Thymeleaf 整合成功,完成了静态资源的引入和动态数据的显示。
实战技能补充:lombok
org.projectlombok
lombok
1.18.12
provided
需求:实现用户的 CRUD 功能
初始化数据库信息:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`
(
id int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
username varchar(100) DEFAULT NULL COMMENT '用户名',
password varchar(100) DEFAULT NULL COMMENT '密码',
birthday varchar(100) DEFAULT NULL COMMENT '生日',
PRIMARY KEY (id)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES (1, 'zhangsan', '123', '2020-10-1');
INSERT INTO `user` VALUES (2, 'lisi', '123', '2020-10-2');
INSERT INTO `user` VALUES (3, 'wangwu', '123', '2020-10-10');
INSERT INTO `user` VALUES (4, 'yuanjing', '123', '2020-10-11');
1)创建 springboot 工程
使用 Spring Initializr 新建一个工程 springbootuser,选择依赖:Developer Tools -> Lombok,Web -> Spring Web,SQL -> [MyBatis Framework、MySQL Driver]。
2)编辑 pom.xml
com.alibaba
druid
1.1.3
3)User 实体类编写
使用 FreeMyBatis 生成实体类。
使用 FreeMyBatis 生成 UserMapper 相关的代码。
com.zm.pojo.User
@Data // Lombok 自动生成 getter 和 setter
public class User implements Serializable {
/**
* 用户id
*/
private Integer id;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 生日
*/
private String birthday;
private static final long serialVersionUID = 1L;
}
4)UserMapper 编写及 xml 文件
com.zm.mapper.UserMapper
public interface UserMapper {
int deleteByPrimaryKey(Integer id);
int insert(User record);
int insertSelective(User record);
User selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record);
}
src\main\resources\mapper\UserMapper.xml
id, username, `password`, birthday
delete from user
where id = #{id,jdbcType=INTEGER}
insert into user (username, `password`, birthday
)
values (#{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{birthday,jdbcType=VARCHAR}
)
insert into user
username,
`password`,
birthday,
#{username,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR},
#{birthday,jdbcType=VARCHAR},
update user
username = #{username,jdbcType=VARCHAR},
`password` = #{password,jdbcType=VARCHAR},
birthday = #{birthday,jdbcType=VARCHAR},
where id = #{id,jdbcType=INTEGER}
update user
set username = #{username,jdbcType=VARCHAR},
`password` = #{password,jdbcType=VARCHAR},
birthday = #{birthday,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
5)UserService 接口及实现类编写
com.zm.service.UserService
public interface UserService {
/**
* 查询所有
*/
List queryAll();
/**
* 通过 ID 查询
*/
User findById(Integer id);
/**
* 新增
*/
void insert(User user);
/**
* 通过 ID 删除
*/
void deleteById(Integer id);
/**
* 修改
*/
void update(User user);
}
com.zm.service.impl.UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List queryAll() {
return userMapper.queryAll();
}
@Override
public User findById(Integer id) {
return userMapper.selectByPrimaryKey(id);
}
@Override
public void insert(User user) {
// 将除 id 外所有的列都拼接入 SQL 语句
// userMapper.insert(user);
// 只将不为空的列才拼接入 SQL 语句(优先使用,减少高并发下数据传输)
userMapper.insertSelective(user);
}
@Override
public void deleteById(Integer id) {
userMapper.deleteByPrimaryKey(id);
}
@Override
public void update(User user) {
userMapper.updateByPrimaryKeySelective(user);
}
}
6)UserController 编写
com.zm.controller.UserController
/**
* restful 格式进行访问
* 查询:GET
* 新增: POST
* 更新:PUT
* 删除: DELETE
*
* @author ZM
* @since 202`-10-31 1:36
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 查询所有
*/
@GetMapping("/query")
public List queryAll(){
return userService.queryAll();
}
/**
* 通过 ID 查询
*/
@GetMapping("/query/{id}")
public User queryById(@PathVariable Integer id){
return userService.findById(id);
}
/**
* 删除
*/
@DeleteMapping("/delete/{id}")
public String delete(@PathVariable Integer id){
userService.deleteById(id);
return "删除成功";
}
/**
* 新增
*/
@PostMapping("/insert")
public String insert(User user){
userService.insert(user);
return "新增成功";
}
/**
* 修改
*/
@PutMapping("/update")
public String update(User user){
userService.update(user);
return "修改成功";
}
}
7)全局配置文件 application.yml
重命名 application.properties 为 application.yml
src\main\resources\application.yml
# 服务器配置
server:
port: 8090
spring:
# 数据源配置
datasource:
name: druid
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/springbootdata?characterEncoding=utf-8&serverTimezone=UTC
username: root
password: password
# 整合 MyBatis
mybatis:
# 声明 MyBatis 文件所在的位置
mapper-locations: classpath:mapper/*Mapper.xml
8)启动类
com.zm.SpringbootuserApplication
@SpringBootApplication
// 使用的 Mybatis, 扫描 com.zm.mapper
@MapperScan("com.zm.mapper")
public class SpringbootuserApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootuserApplication.class, args);
}
}
9)使用 Postman 测试
需求:将 Spring Boot 项目使用 maven 指令打成 jar 包并运行测试。
分析
1)添加打包组件将项目中的资源、配置、依赖包打到一个 jar 包中;可以使用 maven 的 package 命令。
2)部署:java -jar 包名
步骤实现
确保 pom.xml 文件中有如下的打包组件:
org.springframework.boot
spring-boot-maven-plugin
部署运行:
java -jar springbootuser-0.0.1-SNAPSHOT.jar