|
|
|
|
@ -24,36 +24,85 @@ import javax.servlet.http.HttpServletRequest;
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 操作日志切面类,用于捕获和处理带有 @OptLog 注解的方法的成功执行,并记录操作日志。
|
|
|
|
|
*/
|
|
|
|
|
@Aspect
|
|
|
|
|
@Component
|
|
|
|
|
public class OperationLogAspect {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 自动注入 Spring 应用上下文,用于发布事件。
|
|
|
|
|
*/
|
|
|
|
|
@Autowired
|
|
|
|
|
private ApplicationContext applicationContext;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 定义一个切入点,匹配所有使用了 @OptLog 注解的方法。
|
|
|
|
|
* 这意味着只有被 @OptLog 注解标记的方法才会被这个切面拦截。
|
|
|
|
|
*/
|
|
|
|
|
@Pointcut("@annotation(com.aurora.annotation.OptLog)")
|
|
|
|
|
public void operationLogPointCut() {
|
|
|
|
|
// 切入点方法体为空,仅用于定义切入点
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 在切入点方法成功执行后执行的方法。
|
|
|
|
|
* 该方法会在带有 @OptLog 注解的方法成功返回后调用,用于记录操作日志。
|
|
|
|
|
*
|
|
|
|
|
* @param joinPoint 切入点对象,包含方法执行的相关信息
|
|
|
|
|
* @param keys 方法的返回值,通常为操作的结果或数据
|
|
|
|
|
*/
|
|
|
|
|
@AfterReturning(value = "operationLogPointCut()", returning = "keys")
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public void saveOperationLog(JoinPoint joinPoint, Object keys) {
|
|
|
|
|
// 获取当前请求的上下文
|
|
|
|
|
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
|
|
|
|
HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST);
|
|
|
|
|
// 从请求上下文中获取 HttpServletRequest 对象
|
|
|
|
|
HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes)
|
|
|
|
|
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
|
|
|
|
|
|
|
|
|
|
// 创建一个 OperationLog 实体对象,用于存储操作日志信息
|
|
|
|
|
OperationLog operationLog = new OperationLog();
|
|
|
|
|
|
|
|
|
|
// 获取方法的签名信息
|
|
|
|
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
|
|
|
|
Method method = signature.getMethod();
|
|
|
|
|
|
|
|
|
|
// 获取类上的 @Api 注解,用于获取操作所属的模块
|
|
|
|
|
Api api = (Api) signature.getDeclaringType().getAnnotation(Api.class);
|
|
|
|
|
|
|
|
|
|
// 获取方法上的 @ApiOperation 注解,用于获取操作的描述
|
|
|
|
|
ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
|
|
|
|
|
|
|
|
|
|
// 获取方法上的 @OptLog 注解,用于获取操作类型
|
|
|
|
|
OptLog optLog = method.getAnnotation(OptLog.class);
|
|
|
|
|
|
|
|
|
|
// 设置操作所属的模块,通常来自 @Api 注解的 tags
|
|
|
|
|
operationLog.setOptModule(api.tags()[0]);
|
|
|
|
|
|
|
|
|
|
// 设置操作类型,来自 @OptLog 注解的 optType
|
|
|
|
|
operationLog.setOptType(optLog.optType());
|
|
|
|
|
|
|
|
|
|
// 设置操作描述,来自 @ApiOperation 注解的 value
|
|
|
|
|
operationLog.setOptDesc(apiOperation.value());
|
|
|
|
|
|
|
|
|
|
// 获取目标类的全限定名和方法名,组合成完整的操作方法名称
|
|
|
|
|
String className = joinPoint.getTarget().getClass().getName();
|
|
|
|
|
String methodName = method.getName();
|
|
|
|
|
methodName = className + "." + methodName;
|
|
|
|
|
operationLog.setRequestMethod(Objects.requireNonNull(request).getMethod());
|
|
|
|
|
|
|
|
|
|
// 设置操作的完整方法名称
|
|
|
|
|
operationLog.setOptMethod(methodName);
|
|
|
|
|
|
|
|
|
|
// 获取请求的方法类型,如 GET、POST 等
|
|
|
|
|
operationLog.setRequestMethod(Objects.requireNonNull(request).getMethod());
|
|
|
|
|
|
|
|
|
|
// 获取请求的 URI,即请求的路径
|
|
|
|
|
operationLog.setOptUri(request.getRequestURI());
|
|
|
|
|
|
|
|
|
|
// 获取方法的参数,如果第一个参数是 MultipartFile 类型,则记录为 "file"
|
|
|
|
|
// 否则,将所有参数序列化为 JSON 字符串
|
|
|
|
|
if (joinPoint.getArgs().length > 0) {
|
|
|
|
|
if (joinPoint.getArgs()[0] instanceof MultipartFile) {
|
|
|
|
|
operationLog.setRequestParam("file");
|
|
|
|
|
@ -61,14 +110,22 @@ public class OperationLogAspect {
|
|
|
|
|
operationLog.setRequestParam(JSON.toJSONString(joinPoint.getArgs()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置方法的返回值,序列化为 JSON 字符串
|
|
|
|
|
operationLog.setResponseData(JSON.toJSONString(keys));
|
|
|
|
|
|
|
|
|
|
// 获取当前登录用户的详细信息,包括用户ID和昵称
|
|
|
|
|
operationLog.setUserId(UserUtil.getUserDetailsDTO().getId());
|
|
|
|
|
operationLog.setNickname(UserUtil.getUserDetailsDTO().getNickname());
|
|
|
|
|
|
|
|
|
|
// 获取客户端的 IP 地址
|
|
|
|
|
String ipAddress = IpUtil.getIpAddress(request);
|
|
|
|
|
operationLog.setIpAddress(ipAddress);
|
|
|
|
|
|
|
|
|
|
// 获取 IP 地址的来源信息,如国家、城市等
|
|
|
|
|
operationLog.setIpSource(IpUtil.getIpSource(ipAddress));
|
|
|
|
|
operationLog.setOptUri(request.getRequestURI());
|
|
|
|
|
|
|
|
|
|
// 通过应用上下文发布一个操作日志事件,以便其他监听器处理
|
|
|
|
|
applicationContext.publishEvent(new OperationLogEvent(operationLog));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|