yl-backend/src/main/java/com/guwan/backend/aspect/OperationLogAspect.java

133 lines
4.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.guwan.backend.aspect;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.guwan.backend.annotation.OperationLog;
import com.guwan.backend.pojo.entity.SysLog;
import com.guwan.backend.mapper.SysLogMapper;
import com.guwan.backend.security.CustomUserDetails;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class OperationLogAspect {
private final SysLogMapper sysLogMapper;
private final ObjectMapper objectMapper;
/**
* 定义切点
*/
@Pointcut("@annotation(com.guwan.backend.annotation.OperationLog)")
public void logPointcut() {
}
/**
* 环绕通知
*/
@Around("logPointcut() && @annotation(operationLog)")
public Object around(ProceedingJoinPoint point, OperationLog operationLog) throws Throwable {
long beginTime = System.currentTimeMillis();
SysLog sysLog = new SysLog();
try {
Object result = point.proceed();
sysLog.setStatus(1);
return result;
} catch (Exception e) {
sysLog.setStatus(0);
sysLog.setErrorMsg(e.getMessage());
throw e;
} finally {
saveLog(point, operationLog, beginTime, sysLog);
}
}
/**
* 保存日志
*/
private void saveLog(ProceedingJoinPoint joinPoint, OperationLog operationLog, long beginTime, SysLog sysLog) {
try {
// 获取当前请求
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
sysLog.setIp(getIpAddress(request));
sysLog.setUserAgent(request.getHeader("User-Agent"));
}
// 获取当前用户信息
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//Java 16+ 模式匹配写法
if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails userDetails) {
sysLog.setUserId(userDetails.getUserId());
sysLog.setUsername(userDetails.getUsername());
}
// 获取方法信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
sysLog.setMethod(className + "." + methodName);
// 获取请求参数
try {
String params = objectMapper.writeValueAsString(joinPoint.getArgs());
sysLog.setParams(params.length() > 2000 ? params.substring(0, 2000) : params);
} catch (Exception e) {
log.error("序列化请求参数失败", e);
sysLog.setParams(Arrays.toString(joinPoint.getArgs()));
}
// 设置操作信息
sysLog.setOperation(operationLog.description());
sysLog.setCreateTime(LocalDateTime.now());
sysLog.setTimeConsuming(System.currentTimeMillis() - beginTime);
// 保存日志
sysLogMapper.insert(sysLog);
} catch (Exception e) {
log.error("记录操作日志失败", e);
}
}
/**
* 获取IP地址
*/
private String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 多个代理的情况第一个IP为客户端真实IP
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
}