AOP
引入依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>写业务类
java
@Service
public class UserService {
public void saveUser() {
System.out.println("保存用户");
}
}写切面
java
@Aspect
@Component
@Slf4j
public class LogAspect {
@Before("execution(* com.bingli.service.*.*(..))")
public void before() {
log.info("方法执行前");
}
@After("execution(* com.bingli.service.*.*(..))")
public void after() {
log.info("方法执行后");
}
}执行结果
调用:
java
userService.saveUser();输出:
java
方法执行前
保存用户
方法执行后execution 表达式
基本格式
java
execution(权限 返回值 包名.类名.方法名(参数))java
execution(* com.bingli.service.*.*(..))
/**
任意返回值
com.bingli.service 包下
任意类
任意方法
任意参数
*/| 注解 | 时机 |
|---|---|
@Before | 方法前 |
@After | 方法后 |
@AfterReturning | 返回后 |
@AfterThrowing | 异常后 |
@Around | 环绕(最强) |
权限认证(自定义注解 + AOP)
java
package com.bingli.duskeval.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 权限校验-自定义注解
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {
/**
* 必须有某个角色
*
* @return
*/
String mustRole() default "";
}java
/**
* 权限校验 AOP
*
*/
@Aspect
@Component
public class AuthInterceptor {
@Resource
private UserService userService;
/**
* 执行拦截
* @param joinPoint
* @param authCheck
* @return
*/
@Around("@annotation(authCheck)")
public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
String mustRole = authCheck.mustRole();
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
// 当前登录用户
User loginUser = userService.getLoginUser(request);
UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole);
// 不需要权限,放行
if (mustRoleEnum == null) {
return joinPoint.proceed();
}
// 必须有该权限才通过
UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole());
if (userRoleEnum == null) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
// 如果被封号,直接拒绝
if (UserRoleEnum.BAN.equals(userRoleEnum)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
// 必须有管理员权限
if (UserRoleEnum.ADMIN.equals(mustRoleEnum)) {
// 用户没有管理员权限,拒绝
if (!UserRoleEnum.ADMIN.equals(userRoleEnum)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
}
// 通过权限校验,放行
return joinPoint.proceed();
}
}java
//使用注解
@AuthCheck(role = "admin")
public void deleteUser() {
}请求响应日志
java
/**
* 请求响应日志 AOP
**/
@Aspect
@Component
@Slf4j
public class LogInterceptor {
/**
* 执行拦截
*/
@Around("execution(* com.bingli.duskeval.controller.*.*(..))")
public Object doInterceptor(ProceedingJoinPoint point) throws Throwable {
// 计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 获取请求路径
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
// 生成请求唯一 id
String requestId = UUID.randomUUID().toString();
String url = httpServletRequest.getRequestURI();
// 获取请求参数
Object[] args = point.getArgs();
String reqParam = "[" + StringUtils.join(args, ", ") + "]";
// 输出请求日志
log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url,
httpServletRequest.getRemoteHost(), reqParam);
// 执行原方法
Object result = point.proceed();
// 输出响应日志
stopWatch.stop();
long totalTimeMillis = stopWatch.getTotalTimeMillis();
log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis);
return result;
}
}