利用AOP的方式自定义注解
使用背景:
公司的维护项目提出一个比较恶心的需求,添加针对系统的人员和部门,企业等不同维度进行考核(考核的标准大体是根据登录、使用系统内部按钮、审批流转等...)大体就是要通过活跃度,这一下懵逼了,这肯定要在不同的接口写业务逻辑了,根据token获取登录人的所属部门等信息,然后获取对应的业务信息;
解决方法:利用AOP自定义注解的方法可以减少很大一部分工作。这里提供一个简单的测试方法,仅仅只起到提示的作用;
一、首先需要在pom文件中集成aop的包
这里如果你想找不同版本的pom依赖:
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.2.6.RELEASE</version> </dependency>
二、Controller层:利用AOP自定义注解的方式解决问题
package com.dongl.controller; import com.dongl.utils.CheckManagement; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author D-L * @Classname AnnotationController * @Version 1.0 * @Description 使用AOP测试自定义注解 controller * @Date 2020/8/4 */ @RestController @RequestMapping("Annotation") public class AnnotationController { @CheckManagement("annotation-one") @GetMapping(value = "annotation") public Boolean Annotation (){ System.out.println("interface start -----------------------------"); return true; } }
三、自定义注解
package com.dongl.utils; import java.lang.annotation.*; /** * @author D-L * @Classname CheckManagement * @Version 1.0 * @Description 自定义注解 * @Date 2020/8/4 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CheckManagement { String value() default ""; }
四、切面类
package com.dongl.utils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * @author D-L * @Classname AnnotationController * @Version 1.0 * @Description 使用AOP测试自定义注解 切面类 * @Date 2020/8/4 */ @Aspect @Component public class CheckManagementAspect { /** * 切入点 * 切入点为包路径下的:execution(public * org.ylc.note.aop.controller..*(..)): * com.dongl.controller包下任意类任意返回值的 public 的方法 * * 切入点为注解的: @annotation(CheckManagement) * 存在 CheckManagement 注解的方法 */ @Pointcut("@annotation(com.dongl.utils.CheckManagement)") private void check() { } /** * 目标方法调用之前执行 * 注意这里不能使用 ProceedingJoinPoint * @param joinPoint */ @Before("check()") public void doBefore(JoinPoint joinPoint) { Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); CheckManagement visitPermission = method.getAnnotation(CheckManagement.class); String value = visitPermission.value(); System.out.println("before--------------"+ value); } /** * 目标方法调用之后执行 * 注意这里不能使用 ProceedingJoinPoint * @param joinPoint */ @After("check()") public void doAfter(JoinPoint joinPoint) { Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); CheckManagement visitPermission = method.getAnnotation(CheckManagement.class); String value = visitPermission.value(); //根据不同的value处理不同的业务 if(value.equals("annotation-one")){ System.out.println("after-处理方式1 :------------------"); }else if (value.equals("annotation-two")){ System.out.println("after-处理方式2 :------------------"); }else if (value.equals("annotation-three")){ System.out.println("after-处理方式3 :------------------"); } System.out.println("after--------------"+ value); } /** * 环绕 * @param proceedingJoinPoint * @return * @throws Throwable */ @Around("check()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("around start --------------------------"); long startTime = System.currentTimeMillis(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod(); CheckManagement visitPermission = method.getAnnotation(CheckManagement.class); String value = visitPermission.value(); Object result = proceedingJoinPoint.proceed(); long endTime = System.currentTimeMillis(); Map<String, Object> infomation = getInfomation(request, proceedingJoinPoint, startTime, endTime); System.out.println("around end --------------------------"); return result; } /** * 处理执行结果 * @param request 请求体 * @param proceedingJoinPoint * @param startTime 开始时间 * @param endTime 结束时间 * @return */ private Map<String ,Object> getInfomation(HttpServletRequest request ,ProceedingJoinPoint proceedingJoinPoint, long startTime, long endTime){ Map<String , Object> map = new HashMap<>(); // 请求 url String url = request.getRequestURL().toString(); map.put("url" , url); // Http method String HttpMethod = request.getMethod(); map.put("HttpMethod" , HttpMethod); // 调用 controller 的全路径以及执行方法 String declaringTypeName = proceedingJoinPoint.getSignature().getDeclaringTypeName(); map.put("declaringTypeName",declaringTypeName); // 调用方法 String method = proceedingJoinPoint.getSignature().getName(); map.put("method",method); // 执行耗时 map.put("time",(endTime - startTime)); return map; } }
五、测试方法:使用postman调用具体的接口
六、测试结果:
around start -------------------------- before--------------annotation-one interface start ----------------------------- around end -------------------------- after-处理方式1 :------------------ after--------------annotation-one
根据测试结果你也可以看出不同类型的方式执行的顺序;