前言:
15天时间可能写不完了emmm.(有亿点点多)。尽力吧只能说,今天写第三天的
今日所学:
- 公共字段的处理
- 文件上传
- 多表关联
- 一些的踩坑点
目录
1.2.自定义切面类AutoFillAspect, 统一拦截
1. 公共字段的处理(梦回AOP)
问题:
有些字段是公共的是公共的却要反复赋值(createTime,createUser等),产生了大量多余的代码,怎么解决呢
解决思路:
处理这些大量冗余重复代码,我们常见的方法有两种:1.AOP(也就是拦截需要处理的功能) 2.抽取到静态类Utils中
这里明显适合第一种
具体实现思路:
通过切面类定位一个自定义注解AutoFill, 继而定位到相应的方法。最后通过反射来添加相应的数值
核心代码展示:
1.1自定义注解@AutoFill
这里注解的作用是为了定位相应需要自动填充功能字段的方法,其中OperationType是enum枚举类。代表着数据库操作类型
1.2.自定义切面类AutoFillAspect, 统一拦截
这里提醒下写上@Aspect注解(作为切面类),@Component(作为一个bean交给spring容器管理)
接着切入点
这里格外提一嘴
我们先定位到mapper包再定位到@AutoFil注解
而不是直接定位查找@AutoFill注解的原因可能是
- 为了缩小查找范围进行性能优化
- 为了显示设计意图
最后我们写切入面方法
在方法前面进行填充,我们使用@before
因为我们要获得方法的操作类型(insert,update)和方法的参数(mapper类中,比如Employee employee)
因此我们先获得方法签名,并由Signature强转为MethodSignature
(注:MethodSignature继承于Signature)
然后调用相应的方法获得数据库类型,方法参数
最后反射注入赋值即可
3.在mapper方法中加入AutoFill注解
思考:
entity为什么要用反射注入,用setter赋值不行吗
答案是不行的,获取的参数类型entity是object类型的,我们并不知道具体传入的是哪个类型(有可能是employee,也又可能是Category或者是其他任何一种数据模型)
2.文件上传
问题:
如何在项目中实现文件上传
解决思路:
采用阿里云OSS作为存储服务,前端通过multipart/form-data格式将文件发送给后端,后端接收文件后调用OSS SDK将文件上传到指定的Bucket并生成访问URL,最后将URL存入数据库对应表中,后续业务直接通过URL访问文件。
好处:避免了本地储存的扩容和维护,确保了文件访问的稳定
核心代码:
先是获取aliossProperties类中各项属性(一一对应yml文件),接着传递给aliossUtil
以此定位指定的Bucket(上传文件),最后在Controller层将返回的OSS请求路径返回给前端
思考:
为什么ailossUtil要用自定义@bean而不是用@Component
答案:
@Component只能构建无参构造函数不能进行构造函数传值(aliossutil需传递四个参数)
但是两个都可以进行@Autowired依赖注入
3.多表关联
问题:
一次操作如何实现多表的数据添加
解决思路:
先是通过一个DTO接收前端数据,在service层拆解后映射到几个表中,为了保证操作的原子性,我们使用@Transactional开启事务,确保所有表全部插入成功或失败。同时,通过mybatis的useGeneratedKeys获取主表自增ID,再手动设置关联表的逻辑外键字段(比如dish_flavor的dishId和dish的Id),避免依赖外键约束。
核心代码:
这里先从dish表中获得Id,在将其以循环的方式添加到flavor表中
记得在mapper中设置useGeneratedKeys为true(因为id是数据库自增生成的,不能直接getId获得)
思考:
为什么设置逻辑外键而不是物理外键
4.一些踩坑点
4.1.service层
service注解在接口加了在实现方法上也得加
4.2.两表关联
1.删除菜品的时候记得两个表都删除(逻辑外键连着呢)
2.修改操作中口味表是否修改了需判断(一个表修改了另一个表不一定要修改)
注意看需求文档中,口味表并没有强制要求修改
如果你在修改操作中没有去修改口味表,但是你依旧传了mapper会报一个SQL语法错误
具体SQL语句就会表现为
update dish_flavor where dish_id = ?
可以看到,set消失了,要修改什么不知道
解决方法很简单:
加个判断不就行了
传过来的有关flavor的数据为空,直接return走人
不为空,在执行下面的flavor.mapper操作