前言
在之前一篇文章中就介绍了如何自己写一个逻辑删除方面的MP自定义插件。
https://blog.csdn.net/DCTANT/article/details/134515180
但是在这篇文章中有个问题,就是如果有些Entity类不需要逻辑删除功能,也就是压根没有del_flag这个字段,那么自动添加了${表别名}.del_flag会导致SQL报错,因此需要一个更优雅的方式解决这个问题。
解决方案
如果有个方法知道哪些类继承了逻辑删除的Base类,说明这些对应的表就存在逻辑删除字段,反之则没有,不需要自动添加逻辑删除的SQL。
还有一点,如果是要与数据库交互的表,那么必然存在@TableName注解,那么我只需要将所有带有@TableName的类全部拿出来,判断其是否继承自逻辑删除的基类,那么问题就能迎刃而解了。
获取所有带有@TableName注解的类
在SpringBoot中Bean的初始化阶段可以使用@PostConstruct注解,当Bean初始化完成就加载到所有@TableName的类。
代码如下所示:
Kotlin
@Component
class TableNameProcessor(
val applicationContext: ApplicationContext
) {
@PostConstruct
fun processAnnotatedClasses() {
// 获取所有带@TableName注解的Bean实例
val beans = applicationContext.getBeansWithAnnotation(TableName::class.java)
for ((beanName, entity) in beans) {
val clazz = entity::class.java
val tableNameAnnotation = clazz.getAnnotation(TableName::class.java)
if (tableNameAnnotation == null) {
continue
}
// INFO: Zhouwx: 2026/1/12 获取表名信息
val tableName = tableNameAnnotation.value
if (entity::class.isSubclassOf(BaseEntity::class)) {
// INFO: Zhouwx: 2026/1/12 如果这是BaseEntity的子类,说明是带有逻辑删除的类,否则不需要逻辑删除
TableLogicDeleteGlobal.tableLogicDeleteMap[tableName] = true
} else {
TableLogicDeleteGlobal.tableLogicDeleteMap[tableName] = false
}
}
}
}
使用applicationContext.getBeansWithAnnotation获取所有带指定注解的类。这里获取到的是一个Map,key为bean的名称,value则是对应的Entity类。使用这个Entity对应的class,获取它的TableName注解。
TableName注解获取到后,可以获取到该类对应的表名。并判断这个类是否继承自BaseEntity类(我的这个类就是逻辑删除的基类)。如果是,说明这张表带有逻辑删除,将表名和true信息存入全局的Map中,直接存储在内存中,方便快速调用。
改造MP自定义逻辑删除插件
只需要改造原来类中的getEqualTo方法即可,这是判断的核心。
Kotlin
if (fromItem is Table) {
val tableName = fromItem.name
val isLogicDelete = TableLogicDeleteGlobal.tableLogicDeleteMap[tableName] ?: return null
if (!isLogicDelete) {
return null
}
}
之后就是判断返回的equalsTo是否为null了,如果为null则不需要加上逻辑删除的相关SQL,如果有则加上。
where要加
Kotlin
if (where == null) {
// INFO: DCT: 2023/11/12 where条件为空,增加一个where,且赋值为 表名.del = 0
equalsTo?.also {
plainSelect.setWhere(equalsTo)
}
} else {
// INFO: DCT: 2023/11/12 普通where,后面直接加上本表的 表名.del = 0
equalsTo?.also {
val andExpression = AndExpression(where, equalsTo)
plainSelect.setWhere(andExpression)
}
// INFO: DCT: 2023/11/12 有子查询的处理子查询
handleWhereSubSelect(where)
}
join也要加
Kotlin
for (join in joins) {
// INFO: DCT: 2023/11/12 获取表别名,并获取 表.del = 0
val rightItem = join.getRightItem()
val equalsTo = getEqualTo(rightItem)
equalsTo?.also {
// INFO: DCT: 2023/11/12 获取on右边的表达式
val onExpression = join.getOnExpression()
// INFO: DCT: 2023/11/12 给表达式增加 and 表.del = 0
val andExpression = AndExpression(onExpression, equalsTo)
val expressions = ArrayList<Expression?>()
expressions.add(andExpression)
// INFO: DCT: 2023/11/12 目前的这个表达式就是and后的表达式了,不用再增加原来的表达式,因为这个and表达式已经包含了原表达式所有的内容了
join.setOnExpressions(expressions)
}
}
至此,更加优雅的逻辑删除插件就做好了,相比于前一版更加智能了。
开源代码
相关代码位置在: