每次进行增加员工或者修改员工之类,有关修改和新增的操作时,要对修改时间、新增时间、修改人、新增人这几个字段进行修改,代码比较重复。
用切面,前置通知,对Mapper中的方法进行捕获。这些都是我们操作的对象中的字段,原本这些字段是在service的实现类中进行赋值。
用注解进行标识,有@AutoFill就表示当前方法要进行捕获,捕获了之后就把那几个字段进行修改。代码只用写一份,只要有注解就会执行这个进行公共属性赋值的代码。
step1 自定义注解AutoFill,用于表示需要进行公共字段自动填充的方法
/**
* 自定义注解
* 用于表示某个方法需要进行字段自动填充
*/
@Target(ElementType.METHOD) //表示用于方法的标识
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
//数据库操作类型:UPDATE、INSERT update和insert要赋值的属性数量不一样,定义这个属性可以用于区分
OperationType value();//注解的属性
}
step2 自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为对象属性赋值
/**
* 自定义切面
* 实现公共字段自动填充处理逻辑
*/
@Aspect
@Component //交给spring容器来管理
@Slf4j
public class AutoFillAspect {
/**
* 切入点
*/
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") //匹配mapper包下的所有类下的所有方法中的 有AutoFill注解的方法
public void autoFillPointCut(){}
/**
* 前置通知
* 在通知中进行公共字段的赋值
*/
@Before("autoFillPointCut()")
public void autoFill(JoinPoint joinPoint){
log.info("开始进行公共字段自动填充...");
//获取到当前拦截到的方法的数据库操作类型
MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
OperationType operationType = autoFill.value();//获得数据库操作类型
//获取到当前被拦截的方法的参数--实体对象
//这个对象已经在service的实现类中被操作过了 例如员工新增这个操作,账号姓名性别等等这些是属性已经在serviceImpl中进行赋值了,但是修改时间、新增时间..这些属性是公共属性、是重复的,我们放到mapper中进行赋值。将mapper中的新增员工方法拦截,然后加上注解,就可以执行这里的代码了。
Object[] args = joinPoint.getArgs();//方法一般不止一个参数,一般将实体类这个参数放在第一个方便获取
if (args == null || args.length == 0){//方法没有参数
return;
}
Object entity = args[0];//获取到实体对象
//准备赋值的数据
LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();
//根据当前不同的操作类型,为对应的属性通过反射来赋值
if (operationType == OperationType.INSERT){
try {
//获取到实体类中的setter操作的方法
Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//通过反射为对象属性赋值
setCreateTime.invoke(entity, now);
setCreateUser.invoke(entity, currentId);
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
e.printStackTrace();
}
}
if (operationType == OperationType.UPDATE){
try {
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
step3 在Mapper的方法上加入AutoFill注解
@AutoFill(OperationType.UPDATE)
void update(Employee employee);
为什么注解加载了mapper中,我的理解是:
serviceImpl中传入的对象是前端传过来的封装好的对象,然后我们会将其封装成实体类,传给mapper,最终在mapper中的方法的参数是我们需要的实体类,最终传入数据库的就是这个实体类。如果采用前置通知,在mapper中的方法执行之前进行最后的封装,这才是完整的实体类。如果要将注解用在serviceImpl中的话,应该采用的是后置通知吧。
标签:mapper,填充,entity,002,AutoFill,公共,注解,class,赋值 From: https://www.cnblogs.com/jyyyy/p/17990656