MyBatis数据持久化
MyBatis ORM框架使用
1.MyBatis
1.1MyBatis是什么
MyBatis 是一款流行的 Java 持久层框架,它提供了一种优雅的方式来将数据库操作和 SQL 语句与 Java 代码分离。MyBatis 的核心思想是通过 XML 或注解方式将 SQL 语句映射到 Java 方法上,从而实现了数据的持久化。
1.2MyBatis的框架设计

1.2.1接口层—和数据库交互的方式
MyBatis和数据库的交互有两种方式:
a.使用传统的MyBatis提供的API;
b. 使用Mapper接口
1.2.1.1使用传统的MyBatis提供的API
传统的方法是传递Statement Id 和查询参数给 SqlSession 对象,使用 SqlSession对象完成和数据库的交互;MyBatis 提供了非常方便和简单的API,供用户实现对数据库的增删改查数据操作,以及对数据库连接信息和MyBatis 自身配置信息的维护操作。

上述使用MyBatis 的方法,是创建一个和数据库打交道的SqlSession对象,然后根据Statement Id 以及参数来操作数据库,这种方式虽然很简单和实用,但是它不符合面向对象语言的概念和面向接口编程的编程习惯。由于面向接口的编程是面向对象的大趋势,MyBatis 为了适应这一趋势,增加了第二种使用MyBatis 支持接口(Interface)调用的方式。
1.2.1.2 使用Mapper接口
MyBatis 将配置文件中的每一个 节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟 节点中的<select|update|delete|insert> 节点项对应,即<select|update|delete|insert> 节点的id值为Mapper 接口中的方法名称,parameterType 值表示Mapper 对应方法的入参类型,而resultMap 值则对应了Mapper 接口表示的返回值类型或者返回结果集的元素类型。

根据MyBatis 的配置规范配置好后,通过SqlSession.getMapper(XXXMapper.class) 方法,MyBatis 会根据相应的接口声明的方法信息,通过动态代理机制生成一个Mapper 实例,我们使用Mapper 接口的某一个方法时,MyBatis 会根据这个方法的方法名和参数类型,确定Statement Id,底层还是通过SqlSession.select(“statementId”,parameterObject);或者SqlSession.update(“statementId”,parameterObject); 等等来实现对数据库的操作,MyBatis 引用Mapper 接口这种调用方式,是为了满足面向接口编程的需要。(其实还有一个原因是在于,面向接口的编程,使得用户在接口上可以使用注解来配置SQL语句,这样就可以脱离XML配置文件,实现“0配置”)。
1.2.2数据处理层
数据处理层可以说是MyBatis 的核心,从大的方面上讲,它要完成三个功能:
a. 通过传入参数构建动态SQL语句;
b. SQL语句的执行以及
c. 封装查询结果集为List
1.2.2.1.参数映射和动态SQL语句生成
动态语句生成可以说是MyBatis框架非常优雅的一个设计,MyBatis 通过传入的参数值,使用 Ognl 来动态地构造SQL语句,使得MyBatis 有很强的灵活性和扩展性。
参数映射指的是对于java 数据类型和jdbc数据类型之间的转换:这里有包括两个过程:查询阶段,我们要将java类型的数据,转换成jdbc类型的数据,通过 preparedStatement.setXXX() 来设值;另一个就是对resultset查询结果集的jdbcType 数据转换成java 数据类型。
1.2.2.2. SQL语句的执行以及封装查询结果集为List
动态SQL语句生成之后,MyBatis 将执行SQL语句,并将可能返回的结果集转换成List 列表。MyBatis 在对结果集的处理中,支持结果集关系一对多和多对一的转换,并且有两种支持方式,一种为嵌套查询语句的查询,还有一种是嵌套结果集的查询。
1.2.3. 框架支撑层
1.2.3.1事务管理机制
事务管理机制对于ORM框架而言是不可缺少的一部分,事务管理机制的质量也是考量一个ORM框架是否优秀的一个标准.
1.2.3.2连接池管理机制
由于创建一个数据库连接所占用的资源比较大, 对于数据吞吐量大和访问量非常大的应用而言,连接池的设计就显得非常重要.
1.2.3.3缓存机制
为了提高数据利用率和减小服务器和数据库的压力,MyBatis 会对于一些查询提供会话级别的数据缓存,会将对某一次查询,放置到SqlSession 中,在允许的时间间隔内,对于完全相同的查询,MyBatis 会直接将缓存结果返回给用户,而不用再到数据库中查找.
1.2.3.4SQL语句的配置方式
传统的MyBatis 配置SQL 语句方式就是使用XML文件进行配置的,但是这种方式不能很好地支持面向接口编程的理念,为了支持面向接口的编程,MyBatis 引入了Mapper接口的概念,面向接口的引入,对使用注解来配置SQL 语句成为可能,用户只需要在接口上添加必要的注解即可,不用再去配置XML文件了,但是,目前的MyBatis 只是对注解配置SQL 语句提供了有限的支持,某些高级功能还是要依赖XML配置文件配置SQL 语句。
1.2.4 引导层
引导层是配置和启动MyBatis 配置信息的方式。MyBatis 提供两种方式来引导MyBatis :基于XML配置文件的方式和基于Java API 的方式。
1.3MyBatis的主要构件及其相互关系
从MyBatis代码实现的角度来看,MyBatis的主要的核心部件有以下几个:
- SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
- Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
- StatementHandler 具体操作数据库相关的handler接口
- ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,
- ResultSetHandler 具体操作数据库返回结果的handler接口
- MappedStatement MappedStatement维护了一条<select|update|delete|insert>节点的封装,
- SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
- BoundSql 表示动态生成的SQL语句以及相应的参数信息
- Configuration 管理mysqlConfig.xml全局配置关系类
1.4MyBatis的入门程序
1.4.1先准备数据库

1.4.2加入mysql驱动依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
</dependency>
|
1.4.3编写mybatis核心配置文件:mybatisConfig.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/students"/>
<property name="username" value="root"/>
<property name="password" value="123123"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/studentMapper.xml"/>
</mappers>
</configuration>
|
1.4.4编写mapper文件和映射的对象类文件
1
2
3
4
5
6
7
8
9
10
11
12
| @Mapper
public interface StudentMapper {
List<Student> queryAll();
}
@Data
public class Student {
private int id;
private String name;
private String gender;
private int age;
}
|
1.4.5编写mapper.xml文件
1
2
3
4
5
6
7
8
9
10
11
| <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.lesson9.mapper.StudentMapper">
<select id="queryAll" resultType="com.example.lesson9.pojo.Student">
select id,name,gender,age from students.test
</select>
</mapper>
|
1.4.6编写mybatis程序代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| package com.example.lesson9;
import com.example.mybatis.pojo.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class mybatisTest {
public static void main(String[] args) throws Exception{
/* 1.加载mybatis的配置文件,初始化mybatis,创建出SqlSessionFactory,是创建SqlSession的工厂
* 这里只是为了演示的需要,SqlSessionFactory临时创建出来,在实际的使用中,SqlSessionFactory只需要创建一次,当作单例来使用*/
InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
//2. 从SqlSession工厂 SqlSessionFactory中创建一个SqlSession,进行数据库操作
SqlSession sqlSession = factory.openSession();
//3.使用SqlSession查询list表
List<Student> result = sqlSession.selectList("queryAll");
System.out.println(result);
}
}
|
1.4.7查看结果

1.5源码分析举例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| SqlSessionFactoryBuilder的build方法解析XML配置,创建SqlSessionFactory实例。
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//通过传入的inputstream进行xml文件配置,并传入sqlsession工厂
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
;
}
}
return var5;
}
|
builder方法的主要作用是从xml文件中读取数据并将其加载到内存中。
接下来,让我们再详细分析第三步操作,即通过 List result = sqlSession.selectList(“queryAll”); 这条语句来获取数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
List var6;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement);
this.dirty |= ms.isDirtySelect();
var6 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, handler);
} catch (Exception var10) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var10, var10);
} finally {
ErrorContext.instance().reset();
}
return var6;
}
|
这段代码的主要功能是通过 this.configuration.getMappedStatement(statement) 方法来获取我们编写的 mapper XML 对象,这样可以为后续的 SQL 拼写和其他操作提供必要的数据和配置信息。
1
2
3
4
5
| public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
|
query方法被反复调用,其中包含了this.creatCatheKey方法,这个方法非常强大,建议课下深入理解其实现原理,它展示了MyBatis的一级缓存机制,大概的内容是在执行sql之前,MyBatis会检查缓存中是否存在这个数据,如果存在,则直接返回缓存中的数据,如果没有,则会执行sql查询,并将结果再次存入缓存中,这就提升了效率,避免下次查询时再次访问数据库,从而有效减轻了数据库的负载压力。
2.springboot
2.1前置知识
springmvc框架:拦截所有请求,并处理请求,分发给相应的处理器,覆盖表述层,实现表述层的简化
restful api的设计规范:一些请求方式(如get,delete,put,post)以及状态码(200表示客户端请求成功,404表示资源不存在,500表示服务器发生不可预期的错误等)
2.2springboot是什么
Spring Boot是一个基于Spring框架的项目,旨在简化Spring应用的初始搭建以及开发过程。Spring Boot 中文文档提供了全面的入门指南和参考信息.
2.3springboot的三层架构
2.3.1三层架构是什么
把各个功能模块划分为表述层,业务逻辑层,和数据访问层三层架构,各层之间采用接口相互访问,并通过对象模型的实体类(pojo)作为数据传递的载体,不同的对象模型实体类一般对应数据库的不同表。而springboot实现的方式依次是controller层,service层和dao(mapper)层。
在我们进行程序设计程序开发时,尽可能让每一个接口、类、方法的职责更单一些(单一职责原则)。
单一职责原则:一个类或一个方法,就只做一件事情,只管一块功能。
这样就可以让类、接口、方法的复杂度更低,可读性更强,扩展性更好,也更好利用后期的维护。
在我们项目开发中呢,可以将代码分为三层:

- 数据访问:负责业务数据的维护操作,包括增、删、改、查等操作。
- 逻辑处理:负责业务逻辑处理的代码。
- 请求处理、响应数据:负责,接收页面的请求,给页面响应数据。

前端发起的请求,由Controller层接收(Controller响应数据给前端)
Controller层调用Service层来进行逻辑处理(Service层处理完后,把处理结果返回给Controller层)
Serivce层调用Dao层(逻辑处理过程中需要用到的一些数据要从Dao层获取)
Dao层操作文件中的数据(Dao拿到的数据会返回给Service层)
2.3.2代码拆分
我们使用三层架构思想,来简单操作一下,项目结构如下:

导入依赖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
|
**控制层:**接收前端发送的请求,对请求进行处理,并响应数据
1
2
3
4
5
6
7
8
9
10
11
| @RestController
@RequestMapping("/user")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping("/list")
public List<Student> getUser(){
List<Student> students = studentService.queryAll();
return students;
}
}
|
**业务逻辑层:**处理具体的业务逻辑
1
2
3
| public interface StudentService {
List<Student> queryAll();
}
|
1
2
3
4
5
6
7
8
| @Service
public class StudentServiceImp implements StudentService {
@Autowired
private StudentMapper studentMapper;
public List<Student> queryAll(){
return studentMapper.queryAll();
}
}
|
**数据访问层:**负责数据的访问操作,包含数据的增、删、改、查
数据访问接口实现
1
2
3
4
5
| @Mapper
public interface StudentMapper {
@Select("select id,name,gender,age from students.test")
List<Student> queryAll();
}
|
实体pojo层
1
2
3
4
5
6
7
| @Data
public class Student {
private int id;
private String name;
private String gender;
private int age;
}
|
配置yml文件
1
2
3
4
5
6
| spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver #?????
url: jdbc:mysql://localhost:3306/students?useSSL=FALSE&serverTimezone=UTC
username: root #??
password: 123123 #??
|
2.4 注解开发
2.4.1SpringbootApplication注解
@SpringBootApplication注解是Spring Boot框架中的核心注解,它的主要作用是简化和加速Spring Boot应用程序的配置和启动过程。
具体而言,@SpringBootApplication注解起到以下几个主要作用:
- 自动配置:@SpringBootApplication注解包含了@EnableAutoConfiguration注解,用于启用Spring Boot的自动配置机制。自动配置会根据应用程序的依赖项和类路径,自动配置各种常见的Spring配置和功能,减少开发者的手动配置工作。它通过智能地分析类路径、加载配置和条件判断,为应用程序提供适当的默认配置。
- 组件扫描:@SpringBootApplication注解包含了@ComponentScan注解,用于自动扫描并加载应用程序中的组件,例如控制器(Controllers)、服务(Services)、存储库(Repositories)等。它默认会扫描@SpringBootApplication注解所在类的包及其子包中的组件,并将它们纳入Spring Boot应用程序的上下文中,使它们可被自动注入和使用。
- 声明配置类:@SpringBootApplication注解本身就是一个组合注解,它包含了@Configuration注解,将被标注的类声明为配置类。配置类可以包含Spring框架相关的配置、Bean定义,以及其他的自定义配置。通过@SpringBootApplication注解,开发者可以将配置类与启动类合并在一起,使得配置和启动可以同时发生。
总的来说,@SpringBootApplication注解的主要作用是简化Spring Boot应用程序的配置和启动过程。它自动配置应用程序、扫描并加载组件,并将配置和启动类合二为一,简化了开发者的工作量,提高了开发效率。
2.4.2@Service,@Controler,@Mapper注解
在Spring Boot中,使用@Service``@Controller注解的类会被自动扫描并注册为Spring容器的Bean,因此可以被其他组件通过依赖注入的方式使用。
@Controller用于标记控制层组件,控制层负责处理用户的HTTP请求,并返回响应。通常,控制层会调用服务层的方法来处理业务逻辑,并将结果返回给用户,而且Spring MVC会识别带有@RequestMapping系列注解的方法,并将其映射为处理特定HTTP请求的方法。
1
2
3
4
5
6
7
8
9
10
11
| @Controller
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping("/list")
public List<Student> getUser(){
List<Student> students = studentService.queryAll();
return students;
}
}
|
@Mapper注解通常用于标记数据访问层的组件,特别是在使用MyBatis时,用于定义与数据库交互的Mapper接口。这个注解不是Spring Boot官方提供的,而是MyBatis提供的,用于指定哪些接口应该被MyBatis处理,并生成相应的代理实现。
2.4.3@Autowired注解实现自动装配
- @Autowired工作流程
- 首先根据所需要的组件类型到 IOC 容器中查找
- 能够找到唯一的 bean:直接执行装配
- 如果完全找不到匹配这个类型的 bean:装配失败
- 和所需类型匹配的 bean 不止一个
- 加入@Qualifier(value = “bean的名称”)后
- 没有 @Qualifier 注解:根据 @Autowired 标记位置成员变量的变量名作为 bean 的 id 进行匹配
- 使用 @Qualifier 注解:根据 @Qualifier 注解中指定的名称作为 bean 的id进行匹配
2.5数据访问与持久化
2.5.1Spring Data JPA
Spring Boot与Spring Data JPA无缝集成,使得数据访问层的开发变得更加简单和高效。以下是一个基本的JPA实体和仓库(Repository)定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
| @Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// getters and setters
}
public interface UserRepository extends JpaRepository<User, Long> {
}
|
在服务类中可以直接注入UserRepository并使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| @Service
public class UserServiceImp implements UserService {
@Autowired
private UserRepository userRepository;
public List<User> findAll() {
return userRepository.findAll();
}
public User save(User user) {
return userRepository.save(user);
}
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User update(Long id, User userDetails) {
User user = userRepository.findById(id).orElseThrow();
user.setName(userDetails.getName());
user.setEmail(userDetails.getEmail());
return userRepository.save(user);
}
public void delete(Long id) {
userRepository.deleteById(id);
}
}
|
2.5.2数据库连接与配置
Spring Boot通过自动配置简化了数据库连接的配置。在application.properties或application.yml文件中配置数据库连接信息即可,这是以application.properties举的例子
1
2
3
4
| spring.datasource.url=jdbc:mysql://localhost:3306/students
spring.datasource.username=root
spring.datasource.password=123123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
2.5.3事务管理
Spring Boot支持声明式事务管理,可以通过@Transactional注解轻松实现事务控制。例如:
1
2
3
4
5
6
7
| @Transactional
public User update(Long id, User userDetails) {
User user = userRepository.findById(id).orElseThrow();
user.setName(userDetails.getName());
user.setEmail(userDetails.getEmail());
return userRepository.save(user);
}
|
2.6Spring Boot的安全机制
在springboot项目中,可以整合springsecurity,可以实现以下功能:
- 简化配置:Spring Boot 通过自动配置机制简化了 Spring Security 的集成,使得开发者可以轻松地添加安全依赖并启用基本的安全设置。
- 灵活的访问控制:Spring Security 提供了细粒度的访问控制,允许开发者根据具体需求定义复杂的访问规则,例如通过
SecurityFilterChain 来定义访问规则。 - 身份验证和授权:Spring Security 提供了强大的身份验证和授权功能,支持多种认证机制,如表单登录、HTTP基本认证、OAuth2等,以及基于角色和权限的访问控制。
- 防御常见安全漏洞:Spring Security 帮助开发者防范SQL注入、跨站脚本攻击(XSS)等常见网络攻击,提高了应用的安全性。
- 内容安全策略(CSP):Spring Security 支持配置内容安全策略,进一步增强了应用的防护能力。
- 高度可定制:Spring Security 是一个高度可定制的安全框架,它主要提供了身份认证和授权功能,允许开发者定义哪些URL需要认证,哪些用户有权访问某些资源等。
- 减少重复代码:Spring Security 提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC、DI和AOP功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
2.6.1导入依赖
1
2
3
4
| <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
|
2.6.2进行配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| @Configuration
public class SecurityConfig {
@Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user")
.password(passwordEncoder.encode("123123")).roles("USER") //定义user用户和密码
.build());
manager.createUser(User.withUsername("admin")
.password(passwordEncoder.encode("123123")).roles("USER", "ADMIN")//定义admin用户和密码
.build());
return manager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 使用BCryptPasswordEncoder进行密码加密
}
// 配置安全过滤链
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/admin/").hasRole("ADMIN") // 只有ADMIN角色可以访问/admin路径
** .requestMatchers("/user/**").hasAnyRole("ADMIN", "USER") // USER和ADMIN角色都可以访问/user路径
.requestMatchers("/").permitAll() // 允许所有用户访问根路径
)
.formLogin(withDefaults()) // 启用表单登录
.logout(withDefaults()); // 启用注销功能
return http.build();
}
}
|
使得admin用户可以访问"/admin/**“和”/user/“的接口,而user用户只能访问"user/“的接口
2.6.3定义接口进行访问
1
2
3
4
5
6
7
8
9
10
11
12
13
| @RestController
public class UserController {
// @Autowired
// private UserService userService;
@GetMapping("/admin/test")
public String adminEndpoint() {
return "Admin!";
}
@GetMapping("/user/test")
public String userEndpoint() {
return "User!";
}
}
|
2.6.4结果
登陆user用户访问admin/test接口,结果就是不能访问

但user可以访问user/test接口

登陆admin用户,可以访问admin/test接口

2.7Spring Boot的监控与管理
2.7.1Spring Boot Actuator
Spring Boot Actuator提供了一系列用于监控和管理Spring Boot应用的端点。这些端点可以用于查看应用的健康状况、环境信息、度量指标等。可以通过引入spring-boot-starter-actuator依赖来启用Actuator功能:
1
2
3
4
| <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
|
在application.yml文件中配置Actuator端点的访问权限:
1
2
3
4
5
6
| management:
endpoint:
web:
exposure:include: health=*
health:
show-details: always
|
2.7.2健康检查与指标监控
Actuator提供了一个/health端点,用于检查应用的健康状况。可以通过实现HealthIndicator接口来自定义健康检查。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| @Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
boolean healthy = checkSomeService();
if (healthy) {
return Health.up().withDetail("service", "available").build();
} else {
return Health.down().withDetail("service", "unavailable").build();
}
}
private boolean checkSomeService() {
// 自定义健康检查逻辑
return true;
}
}
|
2.7.3自定义监控端点
可以通过实现@Endpoint注解来自定义Actuator端点。例如:
1
2
3
4
5
6
7
8
9
10
| @Endpoint(id = "custom")
@Component
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> customEndpoint() {
Map<String, Object> details = new HashMap<>();
details.put("custom", "This is a custom endpoint");
return details;
}
}
|
2.8Spring Boot的测试
2.8.1单元测试与集成测试
Spring Boot提供了强大的测试支持,可以通过引入spring-boot-starter-test依赖来启用测试功能。以下是一个简单的单元测试示例:
1
2
3
4
5
6
7
8
9
10
11
12
| @SpringBootTest
public class StudentServiceTest {
@Autowired
private StudentService studentService;
@Test
public void testFindALL1(){
List<Student> users = studentService.queryAll();
assertNotNull(users);
}
}
|
2.8.2Mock与测试数据
可以使用@MockBean注解来创建Mock对象,并注入到测试上下文中。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| @SpringBootTest
public class StudentServiceTest {
@MockBean
private UserRepository userRepository;
@Autowired
private UserService userService;
@Test
public void testFindAll() {
when(userRepository.findAll()).thenReturn(Collections.emptyList());
List<User> users = userService.findAll();
assertTrue(users.isEmpty());
}
}
|
到这里我们springboot的学习就告一段落了,相信你对springboot有了更深的理解,大家学完上面的内容看试着能不能在上面的项目中实现更多的方法,这是最基础的项目模型,可以去多深入看看能不能实现更多的方法