第八章 Spring Boot 必知知识点
Problem
转换器都有什么功能
转换器(Converter) 的核心功能可以通俗理解为:比如把前端传的字符串转成后端需要的对象
1. 前端请求数据 → 后端参数:解决 “格式不匹配”
2. 后端内部数据转换:解决 “逻辑适配”
3. 后端响应数据 → 前端 / 存储:解决 “输出格式统一”
转换器的 2 个关键特性:自动触发,不用手动调用;支持自定义
web依赖有什么
- Tomcat提供运行环境
- DispatcherServlet负责请求分发(Spring MVC 的核心)
- XML用于配置项目参数
mybatis配置具体含义

这是 Spring Boot 中 MyBatis 的核心配置,用于告诉 MyBatis 如何找到你的实体类(POJO)和 Mapper 映射文件(XML),简化开发时的代码编写。下面逐行拆解含义:
1. mybatis.type-aliases-package: com.guo.pojo
作用:指定「实体类(POJO)的包路径」,让 MyBatis 自动给实体类起「别名」
- 背景:MyBatis 在 XML 映射文件(或注解)中使用实体类时,默认需要写「全类名」(如
com.guo.pojo.User),繁琐且易出错。 - 配置后效果:MyBatis 会扫描
com.guo.pojo包下的所有类,自动将「类名」作为「别名」(不区分大小写,推荐首字母小写)。
示例对比:
- 未配置时(需写全类名):
<!-- XML 中查询返回 User 实体,需写全类名 -->
<select id="getUserById" resultType="com.guo.pojo.User">
select * from user where id = #{id}
</select>
- 配置后(可直接用别名):
<!-- 直接用类名 User 或 user 作为别名,简洁很多 -->
<select id="getUserById" resultType="User">
select * from user where id = #{id}
</select>
注意:
- 别名默认是「类名」(如
User→ 别名user或User,MyBatis 不区分大小写)。 - 若包下有重名类(如
com.guo.pojo.User和com.guo.pojo.admin.User),需手动通过@Alias注解指定唯一别名:
// 在 POJO 类上添加注解,指定别名
@Alias("userInfo")
public class User { ... }
2. mybatis.mapper-locations: classpath:mybatis/mapper/*.xml
作用:指定「MyBatis Mapper 映射文件(XML)的存放路径」,让 MyBatis 自动加载这些文件
核心概念:
-
classpath::表示从项目的「类路径」下查找(Maven 项目中,src/main/resources目录就是类路径根目录)。mybatis/mapper/*.xml:匹配「类路径下mybatis/mapper文件夹中所有.xml后缀的文件」。
- 为什么需要:Mapper 映射文件是用来写 SQL 语句的(如查询、新增、修改),MyBatis 必须找到这些文件才能执行 SQL,否则会报「绑定失败」错误(如
BindingException: Invalid bound statement (not found))。
项目目录结构示例(需对应配置路径):
src/main/resources/ # 类路径根目录
└── mybatis/
└── mapper/ # 映射文件存放目录
├── UserMapper.xml # 符合 *.xml 匹配规则,会被加载
├── OrderMapper.xml # 同样会被加载
└── other/
└── GoodsMapper.xml # 不会被加载(路径不匹配)
补充:
- 若映射文件放在
src/main/resources/mapper/*.xml,配置需改为classpath:mapper/*.xml(路径要和实际存放位置一致)。 - 若使用「纯注解开发」(不写 XML,直接在 Mapper 接口上用
@Select、@Insert等注解),可省略该配置;但如果是「XML + 接口」混合开发,必须配置该路径。
如何启动异步
①想办法告诉spring我们的异步方法是异步的,所以要在方法上添加注解
②去springboot主程序中开启异步注解功能(@EnableAsync)
异步任务,邮件任务,定时任务的学习重点是什么
|
任务类型 |
Spring Boot 中的定位 |
学习重点 |
|
异步任务 |
应用性能优化 |
, , 线程池配置 |
|
邮件任务 |
业务功能实现 |
, |
|
定时任务 |
系统调度管理 |
, , cron表达式 |
result类什么作用
Result<T> 这个类是一个通用的接口返回结果封装类,在后端开发中非常常见,尤其是在 RESTful API 中。它的核心作用是统一接口的返回格式,让前端能够更方便、更规范地处理后端响应。
核心作用
- 统一返回格式:
-
- 无论接口是成功还是失败,都会返回一个包含
code、msg、data三个字段的 JSON 对象。 - 这使得前端不需要针对不同的成功或失败情况编写不同的解析逻辑。
- 无论接口是成功还是失败,都会返回一个包含
- 明确的状态标识:
-
code字段用于标识请求的状态。1代表成功。0或其他数字代表失败,不同的数字可以对应不同的错误类型。- 前端可以通过判断
code的值来快速确定请求是否成功。
- 携带返回数据:
-
- 当请求成功时(
code=1),data字段会包含接口返回的具体业务数据。 - 这个
data字段的类型是泛型<T>,这意味着它可以是任何类型的对象(比如一个用户信息对象、一个商品列表、一个数字等),使得这个Result类具有极高的灵活性和通用性。
- 当请求成功时(
- 提供错误信息:
-
- 当请求失败时(
code!=1),msg字段会包含人类可读的错误信息。 - 这个信息可以直接展示给用户,或者用于开发者调试。
- 当请求失败时(
代码逐行解析
@Data: 这是 Lombok 注解,它会自动为这个类生成getter、setter、toString()、equals()和hashCode()等方法,让代码更简洁。public class Result<T> implements Serializable:
-
Result<T>: 声明这是一个泛型类,T是一个类型占位符,可以在使用时指定具体的类型。implements Serializable: 表示这个类的对象可以被序列化,这在某些场景下(如分布式系统、缓存)是必需的。
private Integer code;: 状态码。private String msg;: 消息描述。private T data;: 泛型数据。
静态工厂方法解析
这些静态方法是 Result 类的核心,它们提供了一种优雅的方式来创建 Result 对象。
public static <T> Result<T> success():
-
- 用于创建一个无数据返回的成功响应。
- 例如,一个删除操作,成功后不需要返回任何数据,只需要告知前端成功即可。
- 它会创建一个
Result对象,将code设置为1。
public static <T> Result<T> success(T object):
-
- 用于创建一个携带数据的成功响应。
- 这是最常用的方法。当查询或创建数据成功后,将获取到的数据对象作为参数传入。
- 它会创建一个
Result对象,将code设置为1,并把传入的object赋值给data字段。
public static <T> Result<T> error(String msg):
-
- 用于创建一个失败响应。
- 当业务逻辑校验失败、数据库操作出错或发生其他异常时,可以调用此方法。
- 它会创建一个
Result对象,将code设置为0,并把传入的错误信息msg赋值给msg字段。 - 注意:这个方法的返回类型是
Result<T>,但它内部创建的是new Result()。在 Java 中,这会被推断为Result<Object>,然后向上转型为Result<T>。这是一个小瑕疵,更严谨的写法应该是new Result<T>()。不过在大多数情况下,由于类型擦除,这并不会导致问题。
在实际应用中的例子
假设你有一个用户控制器 UserController:
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public Result<User> getUserById(@PathVariable Integer id) {
User user = userService.getById(id);
if (user != null) {
// 查询成功,返回用户数据
return Result.success(user);
} else {
// 查询失败,返回错误信息
return Result.error("用户不存在");
}
}
@PostMapping
public Result<User> createUser(@RequestBody User user) {
boolean success = userService.save(user);
if (success) {
// 创建成功,返回创建后的用户信息
return Result.success(user);
} else {
// 创建失败
return Result.error("创建用户失败");
}
}
@DeleteMapping("/{id}")
public Result<Void> deleteUser(@PathVariable Integer id) {
boolean success = userService.removeById(id);
if (success) {
// 删除成功,无需返回数据
return Result.success();
} else {
return Result.error("删除用户失败");
}
}
}
成功响应示例 (getUserById)
{
"code": 1,
"msg": null,
"data": {
"id": 1,
"username": "张三",
"email": "zhangsan@example.com"
}
}
失败响应示例 (getUserById)
{
"code": 0,
"msg": "用户不存在",
"data": null
}
@AutoFill作用是什么
它通常配合 AOP(面向切面编程) 或 MyBatis 插件 实现,在数据新增(INSERT)或更新(UPDATE)时,自动给注解标记的字段赋值,无需手动 set。
一、核心使用场景
日常开发中,几乎所有实体类都有通用字段:
- 新增时需填充:
createTime(创建时间)、createBy(创建人 ID / 名称) - 更新时需填充:
updateTime(更新时间)、updateBy(更新人 ID / 名称)
如果没有 @AutoFill,每次保存 / 修改数据都要手动写:
// 手动填充(重复且繁琐)
user.setCreateTime(new Date());
user.setCreateBy(getCurrentUserId());
user.setUpdateTime(new Date());
user.setUpdateBy(getCurrentUserId());
userMapper.insert(user);
用 @AutoFill 后,只需在字段上加注解,自动填充逻辑会通过切面 / 插件触发:
public class User {
private Long id;
private String username;
// 新增时自动填充:创建时间
@AutoFill(type = OperationType.INSERT)
private Date createTime;
// 新增/更新时都自动填充:更新时间
@AutoFill(type = {OperationType.INSERT, OperationType.UPDATE})
private Date updateTime;
// 新增时自动填充:创建人
@AutoFill(type = OperationType.INSERT)
private String createBy;
// 新增/更新时自动填充:更新人
@AutoFill(type = {OperationType.INSERT, OperationType.UPDATE})
private String updateBy;
}
// 业务代码无需手动 set,直接保存
userMapper.insert(user); // 切面/插件自动填充 createTime、updateTime、createBy、updateBy
二、实现原理(简化版)
@AutoFill 本身只是「标记」,真正的填充逻辑由配套组件实现,核心流程:
- 定义注解:指定该注解可用于字段(
@Target(FIELD)),保留到运行时(@Retention(RUNTIME)),并添加type属性标记需要触发的操作(INSERT/UPDATE)。java运行
// 注解定义示例
@Target(FIELD) // 仅作用于字段
@Retention(RUNTIME) // 运行时可通过反射获取注解信息
public @interface AutoFill {
// 触发填充的操作类型(新增/更新)
OperationType[] type();
}
// 枚举:操作类型
public enum OperationType {
INSERT, UPDATE
}
- 实现填充逻辑:
-
- 方式 1(AOP):拦截
@Service层的保存 / 更新方法,通过反射获取实体类中带@AutoFill的字段,根据操作类型(INSERT/UPDATE)赋值。 - 方式 2(MyBatis 插件):拦截 MyBatis 的
StatementHandler,在 SQL 执行前修改参数(实体类),填充注解字段。
- 方式 1(AOP):拦截
- 触发填充:当执行新增 / 更新操作时,拦截器触发,根据注解的
type属性判断是否需要填充,最终通过反射给字段设值(如new Date()、当前登录用户 ID 等)
@Pointcut作用是什么
没有 @Pointcut,AOP 就不知道该对哪些代码生效;有了它,才能精准定位要增强的目标,再配合 @Before(前置)、@After(后置)等注解执行切面逻辑。
一、核心本质:定义「拦截规则」
@Pointcut 的核心是 表达式,通过表达式明确:
- 拦截哪些类?(如
com.example.service包下的所有类) - 拦截哪些方法?(如所有
save*开头的保存方法、带@AutoFill注解的方法) - 拦截方法的什么特征?(如 public 修饰、参数类型为 XX、返回值为 XX)
它就像一个「过滤器」,只有符合表达式规则的方法执行时,才会触发后续的切面逻辑(比如之前聊的 @AutoFill 自动填充逻辑)。
二、常见使用场景(结合表达式)
1. 最常用:按「包 + 类 + 方法」匹配(execution 表达式)
这是最灵活的方式,通过 execution() 表达式精准匹配方法,语法格式:
execution(访问修饰符 返回值类型 包名.类名.方法名(参数类型) 异常类型)
示例(对应 @AutoFill 场景):
// 定义切入点:拦截 com.example.mapper 包下所有类的 insert*/update* 开头的方法
@Pointcut("execution(* com.example.mapper.*.insert*(..)) || execution(* com.example.mapper.*.update*(..))")
public void autoFillPointcut() {} // 方法体为空,仅作为切入点标识(方法名任意)
// 前置通知:切入点匹配成功后,执行自动填充逻辑
@Before("autoFillPointcut()")
public void doAutoFill(JoinPoint joinPoint) {
// 这里就是之前聊的 @AutoFill 填充逻辑(反射给字段赋值)
System.out.println("执行自动填充...");
}
关键表达式说明:
*:通配符(如*代表任意返回值类型、任意类、任意方法名)com.example.mapper.*:com.example.mapper包下的所有类(不含子包用*,含子包用**)insert*(..):insert开头的方法,(..)代表任意参数(无参 / 有参都匹配)||:逻辑或(同时拦截 insert 和 update 开头的方法)
2. 按「注解」匹配(@annotation 表达式)
拦截所有带指定注解的方法(比如拦截带 @Log 注解的方法做日志记录):
// 定义切入点:所有带 @Log 注解的方法
@Pointcut("@annotation(com.example.annotation.Log)")
public void logPointcut() {}
// 后置通知:方法执行后记录日志
@AfterReturning("logPointcut()")
public void recordLog(JoinPoint joinPoint) {
System.out.println("记录方法执行日志...");
}
3. 按「类注解」匹配(@within 表达式)
拦截所有带指定注解的类中的 所有方法(比如拦截 @Service 注解类的所有方法做事务控制):
// 定义切入点:所有 @Service 注解标注的类的方法
@Pointcut("@within(org.springframework.stereotype.Service)")
public void servicePointcut() {}
// 环绕通知:控制事务(简化示例)
@Around("servicePointcut()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务...");
Object result = joinPoint.proceed(); // 执行目标方法
System.out.println("提交事务...");
return result;
}
三、关键细节
- 切入点方法的要求:
-
- 方法必须是
public(Spring AOP 要求) - 方法体必须为空(仅作为「切入点标识」,逻辑写在
@Before/@After等通知中) - 方法名任意(建议见名知意,如
autoFillPointcut、logPointcut)
- 方法必须是
- 切入点的复用:多个通知(
@Before/@After)可以复用同一个@Pointcut,避免重复写表达式:java运行
// 复用同一个切入点
@Before("autoFillPointcut()")
public void doBefore() {}
@After("autoFillPointcut()")
public void doAfter() {}
- 与之前的
@AutoFill关联:之前聊的@AutoFill自动填充功能,核心就是通过@Pointcut定义切入点(拦截 mapper 的 insert/update 方法),再在@Before通知中通过反射读取@AutoFill注解,给字段赋值 ——@Pointcut是@AutoFill能生效的前提(定位要拦截的方法)
@RabbitListener 注解的核心作用
@RabbitListener 是 Spring AMQP 框架提供的消费者监听注解,核心作用是:
- 声明 “这个方法是 RabbitMQ 队列的消费者”:无需手动编写
channel.basicConsume等底层代码,Spring 会自动帮你完成队列订阅、消息监听、消费回调的逻辑; - 指定监听的队列:通过
queues属性指定要监听的队列名称(支持多个队列,比如queues = {QUEUE1, QUEUE2}); - 自动管理消费者生命周期:Spring 会自动创建消费者连接、处理消息接收后的线程调度,异常时还能配合
@RabbitHandler、重试机制等做更灵活的处理; - 支持高级特性:比如指定消费组、消息转换器、异常处理器、手动确认消息(配合
ackMode属性)等。
- Application程序本身就是个组件
- springboot依赖都是spring-boot-stater开头
- 最开始通过new对象创建对象,给对象赋值;学了spring就@component通过@value来赋值;再学springboot就通过Application.yaml来赋值,需要@ConfigurationProperties(prefix = "")来绑定对象
- xxxxAutoConfigurartion:自动配置类,绑定xxx类;给容器中添加组件,xxxxProperties:封装配置文件中相关属性
- 可以通过debug=true来判断哪些自动配置类生效了
- templates目录下的所有页面,只能通过controller来跳转
- xxxconfiguration是来扩展springmvc,比如视图解析,视图跳转功能
- Spring 会自动扫描
com.shuxuejia.managementsystem包下的所有类,以及子包(默认扫包) - 自定义了国际化资源文件,因此我们需要在SpringBoot配置文件
application.properties中加入以下配置指定我们配置文件的名称
spring.messages.basename=i18n.login
- Spring Boot 不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中,程序员只需自己注入即可使用
- springboot所有配置类都有一个自动配置类,xxxAutoconfiguration;自动配置类都会绑定一个properties配置文件
ConfigurableApplicationContext
- 组件扫描:从
MainApplication.class所在的包开始,递归扫描所有带有@Component及其派生注解(@Controller、@Service、@Repository等)的类,将它们创建为 “Bean” 并注册到容器中 - 自动配置:根据引入的依赖(如
spring-boot-starter-web、spring-boot-starter-data-jpa),自动加载对应的 “自动配置类”(如WebMvcAutoConfiguration配置 Spring MVC、DataSourceAutoConfiguration配置数据库连接池),无需手动编写 XML 或 Java 配置 - Bean 的依赖注入:容器会解析 Bean 之间的依赖关系(如
@Autowired标注的属性或构造方法),自动将依赖的 Bean 注入到目标对象中(例如将UserService注入到UserController)
更多推荐




所有评论(0)