需求:
- 给某些特定的api 打统一规范的log
- 对某些固定的api 做权限校验
进程:
- 权限校验和统一的log 这只有两件事情,如果要在每个api 前面带上校验后面带上log那不改到天都黑了
- 使用 @Aspect 这个注解叫切面,他可以在api 请求的前后做一些额外的事情
- 首先加上aop 的依赖
<artifactId>spring-boot-starter-aop</artifactId>
- 创建一个类标记为 @Aspect
@Aspect @Component public class LogAspect{ }
- 标记这个类是为了哪些api 在方法上加上@Pointcut 做拦截处理
// excution 模式 //表示public 的返回类型为所有类型的 方法在com.controller 包下的所有子包,下的所有方法名,任意参数单api // 第一个 * 表示所有返回类型, controller 后的 .. 表示所有的子包,后面的 * 表示所有的类,.* 表示所有的方法, (..) 表示任意的参数 @Pointcut("execution(public * com.controller..*.*(..))") private void webLog() { } //annotation 模式 //表示针对有 ApiToken 注解的方法使用这个切面 @Pointcut("@annotation(common.annotation.ApiToken)") private void webLog() { }
- 使用 @Around 通过切面开始对api 做统一log
@Around("webLog()") public Object permissionCheck(ProceedingJoinPoint joinPoint) throws Throwable { log.info("start"); // 获取当前请求对象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); for (Object object : joinPoint.getArgs()) { if (object instanceof TokenAuthApi) { TokenAuthApi api = (TokenAuthApi) object; appKey = api.getAppKey(); // 设置body的参数,供统一异常处理时获取 request.setAttribute("appKey", appKey); } } // proceed 表示开始执行原本需要执行的进程,返回的result 是原本应该会返回到前端的数据,proceed 也可以传入参数,传入的参数会完全替换掉之前的参数,要谨慎使用 Object result = joinPoint.proceed(); log.info("end"); // 这边必须要做一个返回,甚至这边可以对result 做一个删减处理,但是不建议在这边对处理做处理 return result; }
- 如果只是期望在切面方法之前调用可以使用 @Before,在之后可以使用@After,不过我觉得,around就可以满足这两个注解的使用,如果是在切面的时候抛出异常可以用@AfterThrowing,在返回之后可以用 @AfterReturning,来捕获方法所有都完成之后的返回值这个方法会多一个参数
@AfterReturning(pointcut = "webLog()", returning = "result") public void doAfterReturning(JoinPoint joinPoint, Object result) { Signature signature = joinPoint.getSignature(); String classMethod = signature.getName(); log.info("方法{}执行完毕,返回参数为:{}", classMethod, result); } @AfterThrowing(pointcut = "webLog()", throwing = "ex") public void afterThrowing(JoinPoint joinPoint, Throwable ex) { Signature signature = joinPoint.getSignature(); String method = signature.getName(); // 处理异常的逻辑 log.info("执行方法{}出错,异常为:{}", method, ex); }
拓展:
- 除了切面还有过滤器,拦截器,监听器