1.❔公共字段自动填充模块多次重复编写
⭐️解决
- ·自定义注解AutoFill,用于标识需要进行公共字段自动填充的方法
- 自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值
- 在Mapper的方法上加入Autoill注解
1.1💻切面与AOP
AOP 是一种编程思想(类似于 OOP 面向对象编程),
目的是将程序中与业务逻辑无关但又普遍存在的功能模块(横切关注点)分离出来,从而实现代码的高内聚、低耦合。
AOP 是一种通过“切面”技术,将横切逻辑动态织入程序运行过程中的编程思想。
“切面”是 AOP 的具体实现载体,定义了“在何处(Pointcut)”以及“做什么(Advice)”。
eg:创建人,创建时间,更新人,更新时间等需要自动填充的公共字段
[系统中所有方法调用]
↓ (连接点全集)
筛选出符合条件的那些方法
↓ (切点 Pointcut)
定义在这些方法执行前/后要做什么
↓ (通知 Advice)
封装成一个切面类
↓ (切面 Aspect)
Spring 在运行时织入增强逻辑
↓ (动态代理生成代理对象)
1.2连接点(jiont point)与切点(pointcut)
连接点:所有可能的拦截点【所有方法的调用】动态
切点:一种挑选连接点的规则,匹配的连接点为拦截点。静态
❔为什么【通知】传进去的参数是joint point 而非 pointcut
- AOP包含切面+切点+通知【增强逻辑】
- 先定义切点【规则】,接着定义通知【在调用方法上检测该方法是否满足切点定义的规则,如果满足,执行通知,该过程由SPRING AOP自动执行】,所以通知作用在切点上但是执行操作的是当前连接点。
1.3 切点的拦截路径
扫描的路径,* com.sky.mapper..(…),mapper完整的路径是sky-take-out/sky-server/mapper,当前切面的路径是sky-take-out/sky-server/aspect,为什么只写了sky.mapper就能找到呢?
因为SPRING扫描时是按照【包声明】而非物理路径,每个mapper文件上面写了声明 page com.sky.mapper.
1.4 为什么获取数据库的操作类型可以用Joinpoint.getsignature?,又为什么要把signature方法转为methodsignature接口?
一句话:在AOP里面传递信息要通过反射对象【method】
问题1:==JoinPoint== 保存了完整的上下文,包括:
- 目标对象(target)
- 代理对象(proxy)
- 方法参数(args)🍁
- 签名信息(signature)🍁
- 当前执行点的静态和动态数据
signature里面保存的是通用签名信息,只描述方法结构,不具备反射能力
-
方法名(
getName()) -
所属类名(
getDeclaringType())【我们获取的数据库操作类型属于这一类】 -
修饰符(
getModifiers())
但是它不能拿到反射对象【method】,只有子接口MethodSignature(从上继承)能得到method对象
method对象可以
通过 getAnnotation() 获取注解;🍁本次需要的
通过 getReturnType() 获取返回类型;
通过 invoke() 执行反射调用;
通过 getParameters() 获取参数名类型等。
1.5反射对象指的就是method吗?还有其他的反射对象吗?是不是切面的通知里面想要执行增强逻辑,必须通过反射对象?
-
反射是指是指程序在运行时能够:动态地检查类的信息;动态地调用方法;动态地修改属性;动态地创建对象。包含
Class、Field、Method、Constructor等。 -
Spring AOP 拦截的连接点(JoinPoint)主要是 方法调用, 所以绝大多数场景下我们用到的是
Method反射对象。 -
AOP执行逻辑增强有两种
-
1.不依赖反射如打印日志
```java@Before(“controllerMethods()”)
public void logStart(JoinPoint joinPoint) {
log.info(“方法开始执行: {}”, joinPoint.getSignature().getName());
}
``` -
2.依赖反射(基于注解或方法)如动态修改执行逻辑
-
1.6 为什么是get annonation传入的是(AutoFill.class);
Java 一切类型(class、interface、enum、annotation)都对应一个 Class 对象,把 .class 看作是「把类型本身当作对象来使用」的语法糖。
Class c1 = User.class; // 普通类
Class c2 = Runnable.class; // 接口
Class c3 = AutoFill.class; // 注解类型
Class c4 = int.class; // 基本类型
1.7 为什么要通过反射来复制,不能直接set赋值吗?Method setCreateTime = entity.getClass().getDeclaredMethod(“setCreateTime”, LocalDateTime.class);
直接调用 entity.setXXX() 就会在编译期间执行,entity 必须是具体的实体类;
如果使用反射,这里的 entity 编译时只是一个‘占位符’,编译时只知道是object类型
当运行时根据传进来的对象动态填充,只要里面有这个方法即可调用。
反射让 AOP 的切面逻辑可以在不知道具体类型的前提下,对不同实体动态地执行相同的操作。
1.8总结component+bean+autowired与工具类实例化
| 工具类类型 | 特点 | 依赖 | 生命周期 | 创建方式 | 是否需要实例化 |
|---|---|---|---|---|---|
| 无状态工具类 | 所有方法静态 | 无 | 由 JVM 类加载即可 | 不需要 Spring | NO |
| 普通组件类/切面类 | 有成员变量 | Spring 环境 | 由 Spring 容器创建 | @Component | YES |
| 依赖外部 Bean 的工具类 | 有成员变量 | Spring 环境由 Spring 容器创建 | @Configuration + @Bean | YES |
Spring 容器(IoC 容器)的本质:
管理对象(Bean)的创建、初始化、依赖关系、销毁。
所以要让对象被自动注入(@Autowired),
必须先让它进入 Spring 容器。
而“进入容器”的两种主要方式就是:
-
方式1:
@Component -
方式2:
@Configuration + @Bean
| 注解 | 作用 | 使用场景 | 是否自动扫描 | 是否可被注入 |
|---|---|---|---|---|
@Component | 把类交给 Spring 扫描并创建实例 | 类本身可直接被管理(普通组件、切面、工具类等) | ✅ 是(通过包扫描) | ✅ 可被 @Autowired 注入 |
@Bean | 在配置类中手动注册一个 Bean | 类不能直接扫描或需要自定义构造 | ❌ 否(需在 @Configuration 中声明) | ✅ 可被 @Autowired 注入 |
@Autowired | 从容器中获取 Bean 并注入到当前类 | 依赖 Bean 的地方(Controller、Service、Util) | N/A | ✅ 用于使用 Bean |
❔2.菜品批量删除
1.调试报错:500
控制台输出:
nested exception is java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List] with root cause
解决:1.检查mapper文件参数传递
2.检查controller方法里面 @RequestParam,不加 @RequestParam → Spring 试图构造 List 对象 → 失败 → 500
public Result delete(@RequestParam List<Long> ids){}
//告诉Spring把表单参数自动转为list
总之:json格式(1,2,)用@RequesBody,query格式(地址栏格式value?)用@RequestParam
| 注解 | 参数来源 | 请求体格式 | 常见场景 |
|---|---|---|---|
@RequestParam | URL 查询参数 / 表单 | ?ids=1&ids=2&ids=3 | GET、DELETE |
@RequestBody | HTTP Body | JSON,例如 [1,2,3] | POST、PUT、DELETE(携带 body) |
❔3.菜品修改
⛏controller 里面的参数注解
- @PathVariable : 路径参数,用于 URL 路径变量,eg @PathVariable id,根据id查询菜品/dish/{id}
- @RequestBody:接收前端[json格式]的数据,eg { “name”: “红烧肉”, “price”: 22.5 }
- @RequesParam:用于 URL 查询参数(多个),spring自动把表单拆分为list,eg,批量删除,从前端获取id组合,/dish?ids=1&ids=2
⛏controller 传给前端的两种Result泛型
- VO:其他需要回显时,例如根据id查
- PageResult:分页
⛏口味表的修改操作==先删除所有,再重新插入【因为修改有很多不确定性】
⛏就算有公共字段自动填充(自定义AOP切面类)也要再sql实现里面写对应sql语句,sql指明哪些字段需要更新,自动填充负责赋值
⛏如果(service)某项操作涉及到多个表,需要使用事务注解@Transcation

1142

被折叠的 条评论
为什么被折叠?



