利用AOP实现公共字段注入
场景
利用AOP实现Mapper层操纵数据库时的公共字段填充,例如: -创建时间 -更新时间 -创建用户 -更新用户
代码
创建注解辅助AOP精准定位切入点,OperateType
为区别AOP实际增强业务。
public enum OperateType {
INSERT,
UPDATE,
USERID;
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
/**
* 数据库操作类型,INSERT插入操作,UPDATE更新操作
*/
OperateType[] value();
}
创建切面类
// Aspect注解标识
@Aspect
@Component
public class AutoFillAspect {
// 切点定义 任何返回值 任何类的任何方法(方法的参数任意) 必须有`AutoFill`注解
@Pointcut("execution(* com.bilubi.reggie.reggie.mapper.*.*(..)) && @annotation(com.bilubi.reggie.reggie.annotation.AutoFill)")
public void autoFillPointcut() {
}
// 前置通知
@Before("autoFillPointcut()")
public void autoFill(JoinPoint joinPoint) {
//获取方法签名对象
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取注解对象
AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);
//获取数据库操作类型
OperateType[] operateType = autoFill.value();
//获取拦截方法实体类对象参数
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) {
return;
}
Object entity = args[0];
//获取参数类型
Class<?> entityClass = entity.getClass();
//获取填充数据
Long createUserId = BaseContext.getValue();// 当前用户名
Date now = new Date();// 当前时间
log.info("时间:{}", now.toString());
for (OperateType operateType_ : operateType) {
//为插入操作填充数据
if (operateType_ == OperateType.INSERT) {
try {
if (List.class.isAssignableFrom(entityClass)) {
for (Object object : (List<?>) entity) {
Method setCreateUser = object.getClass()
.getMethod("setCreateUser", Long.class);
Method setUpdateUser = object.getClass()
.getMethod("setUpdateUser", Long.class);
Method setCreateTime = object.getClass()
.getMethod("setCreateTime", Date.class);
Method setUpdateTime = object.getClass()
.getMethod("setUpdateTime", Date.class);
setCreateUser.invoke(object, createUserId);
setUpdateUser.invoke(object, createUserId);
setCreateTime.invoke(object, now);
setUpdateTime.invoke(object, now);
}
}
else {
Method setCreateUser = entity.getClass()
.getMethod("setCreateUser", Long.class);
Method setUpdateUser = entity.getClass()
.getMethod("setUpdateUser", Long.class);
Method setCreateTime = entity.getClass()
.getMethod("setCreateTime", Date.class);
Method setUpdateTime = entity.getClass()
.getMethod("setUpdateTime", Date.class);
setCreateUser.invoke(entity, createUserId);
setUpdateUser.invoke(entity, createUserId);
setCreateTime.invoke(entity, now);
setUpdateTime.invoke(entity, now);
}
} catch (Exception ex) {
throw new RuntimeException();
}
}
//为更新操作填充数据
if (operateType_ == OperateType.UPDATE) {
try {
if (List.class.isAssignableFrom(entityClass)) {
for (Object object : (List<?>) entity) {
Method setUpdateUser = object.getClass()
.getMethod("setUpdateUser", Long.class);
Method setUpdateTime = object.getClass()
.getMethod("setUpdateTime", Date.class);
setUpdateUser.invoke(object, createUserId);
setUpdateTime.invoke(object, now);
}
}
else {
Method setUpdateUser = entity.getClass()
.getMethod("setUpdateUser", Long.class);
Method setUpdateTime = entity.getClass()
.getMethod("setUpdateTime", Date.class);
setUpdateUser.invoke(entity, createUserId);
setUpdateTime.invoke(entity, now);
}
} catch (Exception ex) {
throw new RuntimeException();
}
}
//为user对象填充uesrID
if (operateType_ == OperateType.USERID){
try {
Method method = entityClass.getMethod("setUserId", Long.class);
method.invoke(entity, createUserId);
}
catch (Exception ex) {
throw new RuntimeException();
}
}
}
}
}
AOP切面类的其他通知类型
@Aspect
@Component
public class AopAdvice {
@Pointcut("execution (* com.shangguan.aop.controller.*.*(..))")
public void test() {
}
@Before("test()")
public void beforeAdvice() {
System.out.println("beforeAdvice...");
}
@After("test()")
public void afterAdvice() {
System.out.println("afterAdvice...");
}
@Around("test()")
public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("before");
try {
proceedingJoinPoint.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("after");
}
}