回顾AOP切面编程
获取方法名、参数值、参数值类型、目标注解对象、目标方法所在类、返回值类型
1. 引入Maven依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
2. 创建一个自定义注解类CacheableTest
1 2 3 4 5 6 7 8
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface CacheableTest { String key(); String value() default ""; int expireTime() default 3600; }
|
3. 创建一个controller类,并加入该方法
1 2 3 4 5 6
| @RequestMapping("/findPage2") @CacheableTest(key="haha",value = "hehe") public String findPage2(Integer pageNumber, Double pageSize){ System.out.println("findPage2请求成功!!!"); return "请求成功"; }
|
4. 创建一个切面类 TestAOP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Component @Aspect public class TestAop {
@Pointcut("execution(public * ink.lusy.helloController.*(..))") private void pointCut(){};
@Before(value = "pointCut()") public void logBefore(JoinPoint joinpoint) { System.out.println("----------Before开始-----------");
System.out.println("方法名:"+ joinpoint.getSignature().getName()); System.out.println("参数值集合:"+ Arrays.asList(joinpoint.getArgs())); System.out.println("参数值1类型:"+ joinpoint.getArgs()[0].getClass().getTypeName()); System.out.println("参数值2类型:"+ joinpoint.getArgs()[1].getClass().getTypeName()); String classType = joinpoint.getTarget().getClass().getName(); System.out.println("获取目标方法所在类:"+ classType); MethodSignature methodSignature = (MethodSignature) joinpoint.getSignature(); CacheableTest cacheable = methodSignature.getMethod().getAnnotation(CacheableTest.class); Class returnType = methodSignature.getReturnType(); System.out.println("目标注解对象:"+ cacheable); System.out.println("返回值类型 = " + returnType); System.out.println("----------Before结束-----------");
}
@After(value = "pointCut()") public void logAfter(JoinPoint joinpoint) { System.out.println("---------After开始------------");
System.out.println("---------After结束-------------"); }
}
|
执行结果:

在请求时pageSize写的是1,这里自动转成1.0
具体实现
问题复现
在添加、修改 管理员、用户、菜品
等数据时,总是要重复的修改相同的字段:CreateTime
、UpdateTime
、CreateUser
、UpdateUser
解决方案
使用AOP切面编程在施行对应的新增、修改 SQL语句之前,给对应字段做出统一的处理
具体流程
- 引入Maven依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
- 创建一个枚举类OperationType:区分新增、更新操作
1 2 3 4 5 6
| public enum OperationType { UPDATE, INSERT }
|
- 创建一个自定义注解类AutoFill:自定义注解,用于标识某个方法需要进行功能字段自动填充处理
1 2 3 4 5 6 7 8 9
| @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill { OperationType value();
}
|
- 创建一个切面类 AutoFillAspect:自定义切面,实现公共字段自动填充处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| @Aspect @Component @Slf4j public class AutoFillAspect {
@Pointcut("execution(* com.sky.mapper.*.*(..)) && " + "@annotation(com.sky.annotation.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();
Object[] args = joinPoint.getArgs(); if (args <mark> null || args.length </mark> 0) { return; }
Object entity = args[0];
LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId();
if (operationType == OperationType.INSERT) { try { 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 (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } }else 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(); } } System.out.println(entity); } }
|
- 使用示例:
1 2 3 4 5
| @Insert("insert into employee (name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user) " + "VALUES " + "(#{name},#{username}, #{password}, #{phone}, #{sex}, #{idNumber}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})") @AutoFill(value = OperationType.INSERT) void insert(Employee employee);
|