You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
4.1 KiB

  1. package com.example.demo.RabbitMQ;
  2. import com.example.demo.Util.SecurityUtils;
  3. import com.example.demo.config.RabbitMQConfig;
  4. import com.example.demo.config.interfac.Log;
  5. import com.example.demo.domain.DTO.OperationLogDTO;
  6. import com.fasterxml.jackson.databind.ObjectMapper;
  7. import jakarta.servlet.http.HttpServletRequest;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.aspectj.lang.ProceedingJoinPoint;
  10. import org.aspectj.lang.annotation.Around;
  11. import org.aspectj.lang.annotation.Aspect;
  12. import org.aspectj.lang.reflect.MethodSignature;
  13. import org.springframework.amqp.rabbit.core.RabbitTemplate;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.stereotype.Component;
  16. import org.springframework.web.context.request.RequestContextHolder;
  17. import org.springframework.web.context.request.ServletRequestAttributes;
  18. import java.time.LocalDateTime;
  19. // com.example.demo.aspect.LogAspect.java
  20. @Aspect
  21. @Component
  22. @Slf4j
  23. public class LogAspect {
  24. @Autowired
  25. private RabbitTemplate rabbitTemplate;
  26. @Around("@annotation(com.example.demo.config.interfac.Log)")
  27. public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
  28. long startTime = System.currentTimeMillis();
  29. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  30. String methodName = signature.getName();
  31. String className = signature.getDeclaringTypeName();
  32. Object[] args = joinPoint.getArgs();
  33. Log logAnnotation = signature.getMethod().getAnnotation(Log.class);
  34. String action = logAnnotation.value();
  35. // ✅ 使用 Spring Security 获取真实用户
  36. String username = SecurityUtils.getCurrentUsername();
  37. Integer userId = SecurityUtils.getCurrentUserId();
  38. // 添加空值检查
  39. if (userId == null) {
  40. log.warn("无法获取当前用户ID,使用默认值 -1");
  41. userId = -1; // 或者使用其他默认值
  42. }
  43. String ip = getClientIp();
  44. ObjectMapper mapper = new ObjectMapper();
  45. String argsJson = "[]";
  46. try {
  47. argsJson = mapper.writeValueAsString(args);
  48. } catch (Exception e) {
  49. argsJson = "serialize failed";
  50. }
  51. Object result;
  52. try {
  53. result = joinPoint.proceed();
  54. } catch (Exception e) {
  55. log.error("方法执行异常: {}", e.getMessage());
  56. throw e;
  57. }
  58. long duration = System.currentTimeMillis() - startTime;
  59. // ✅ 构造日志消息 DTO
  60. OperationLogDTO logDTO = new OperationLogDTO();
  61. logDTO.setUserId(userId);
  62. logDTO.setUsername(username);
  63. logDTO.setAction(action);
  64. logDTO.setIp(ip);
  65. logDTO.setMethod(methodName);
  66. logDTO.setArgs(argsJson);
  67. logDTO.setCreateTime(LocalDateTime.now());
  68. System.out.println(logDTO);
  69. // ✅ 发送消息到 RabbitMQ(不等待)
  70. try {
  71. rabbitTemplate.convertAndSend(RabbitMQConfig.LOG_EXCHANGE, "log.save", logDTO);
  72. log.info("📩 日志消息已发送到 RabbitMQ: {}", action);
  73. } catch (Exception e) {
  74. log.error("发送日志消息到 RabbitMQ 失败", e);
  75. }
  76. log.info("✅ AOP 拦截完成: {} 执行 [{}] 耗时 {}ms", username, action, duration);
  77. return result;
  78. }
  79. private String getClientIp() {
  80. try {
  81. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
  82. String ip = request.getHeader("X-Forwarded-For");
  83. if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
  84. ip = request.getHeader("Proxy-Client-IP");
  85. }
  86. if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
  87. ip = request.getHeader("WL-Proxy-Client-IP");
  88. }
  89. if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
  90. ip = request.getRemoteAddr();
  91. }
  92. return ip.split(",")[0].trim(); // 多代理时取第一个
  93. } catch (Exception e) {
  94. return "unknown";
  95. }
  96. }
  97. }