目录
- 背景
- 分析
- 代码
背景
需求:对现有系统中所有数据库表都建立一张对应的备份表;在对主表进行增加,修改,删除操作的同时对备份表进行相同的操作。首先想到的应该是备份一个数据库就完事了~不过实际情况没这么简单,总之需要建立对应的备份表。就比如现在有:A,B,C,D四张表,那就建立A1,B1,C1,D1四张备份表(备份表比主表多一个字段,备份表的主键ID)。在前台对A表进行增删改操作,在A1表中要同步对A表的操作。比如A表新增一条数据,那么A1表要同步新增一条数据;修改,删除操作同样如此。
现有系统已经实现了对A表的增删改操作,在现有系统上直接修改代码也可以实现。比如在新增的方法中,添加对备份表的新增。在删除的方法新增对备份表的删除,这样也可以实现目的。但是这样做工作量就比较大。
想一下:增加,修改,删除这3个动作,主表跟备份表是一样的,这就有可能使用注解来解决这种重复的操作。
分析
先来看一下【增加】动作,伪代码可以写成下面的样子
//主表
public Entity insert(XXVO vo){//do something....xxService.save(entity);return entity;
}
现在要做的就是在这个基础上再给备份表新增一条数据,那么备份表的新增就很简单了
//主表
public Entity insert(XXVO vo){//do something....xxService.save(entity);BackupEntity copy = BeanUtil.copy(entity,BackupEntity.class);xxBackupService.save(copy)return entity;
}
我们在对备份表新增时做了哪些操作呢?
- 1.拿到主表的实体对象copy一份,将主表的数据对象copy成备份实体对象
- 2.用备份表对应的Service对象去保存备份实体数据
如果把这2步操作简化成用注解来完成:
- 1.要取到主表保存后的entity对象;
- 2.要知道对应的备份实体是什么类
- 2.要获取到对应备份表的service对象;
对应的解决办法:
- 1.可以通过@AfterReturning注解,获取到新增方法的返回值entity对象;
- 2.在注解上增加属性:backupClass这个值是备份表的实体class对象,在解析注解的时候可以获取到这个属性值来生成对应的备份实体对象
- 3.在注解上增加backupServiceClass属性;然后通过手动获取spring容器对象的方式来获取备份表的service对象。
代码
实体类
/**** 主表*/
@Data
@TableName("sync_table")
public class SyncTable implements Serializable {@TableId(value = "id")private String mainId;private String f1;private String f2;private String f3;private String f4;
}/**** 备份表*/
@Data
@TableName("sync_table_backup")
public class SyncTableBackup implements Serializable {@TableId(value = "id")private String backupId;private String mainId;private String f1;private String f2;private String f3;private String f4;
}
注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface SyncInsert {/*** * 备份表实体对象class* @return*/Class backupClass();/*** * 备份表的service对象class* @return*/Class backupServiceClass();
}
上面分析的时候提到要手动获取spring容器的对象,那么首先要获取到spring的容器对象ApplicationContext ,通过实现ApplicationContextAware
@Component
public class SpringBeanFactory implements ApplicationContextAware {//spring容器private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public ApplicationContext getApplicationContext(){return this.applicationContext;}
}
解析自定义注解SyncInsert
@Aspect
@Component
public class SyncInsertAspect {@AutowiredSpringBeanFactory beanFactory;private ApplicationContext getApplicationContext(){return beanFactory.getApplicationContext();}@AfterReturning(value = "@annotation(com.example.demos.annotaions.SyncInsert)",returning = "entity")public void syncInsert(JoinPoint joinPoint,Object entity){MethodSignature signature = (MethodSignature)joinPoint.getSignature();SyncInsert syncInsert = signature.getMethod().getAnnotation(SyncInsert.class);Class backupServiceClass = syncInsert.backupServiceClass();IService backupService = (IService)getApplicationContext().getBean(backupServiceClass);Class backupClass = syncInsert.backupClass();Object backup = BeanUtil.copyProperties(entity, backupClass);backupService.save(backup);}}
修改,删除动作也差不多就不再赘述了。