2025-05-03 02:20:50 +00:00
|
|
|
|
package com.greenorange.promotion.aop;
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
2025-05-03 07:03:36 +00:00
|
|
|
|
import com.greenorange.promotion.annotation.SysLog;
|
2025-05-03 02:20:50 +00:00
|
|
|
|
import com.greenorange.promotion.model.entity.SysOperLog;
|
|
|
|
|
import com.greenorange.promotion.service.log.SysOperLogService;
|
|
|
|
|
import jakarta.annotation.Resource;
|
|
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
|
|
import org.aspectj.lang.JoinPoint;
|
|
|
|
|
import org.aspectj.lang.annotation.*;
|
|
|
|
|
import org.aspectj.lang.reflect.MethodSignature;
|
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
import org.springframework.web.context.request.RequestAttributes;
|
|
|
|
|
import org.springframework.web.context.request.RequestContextHolder;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
import java.net.HttpURLConnection;
|
|
|
|
|
import java.net.URL;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 切面处理类,记录操作日志到数据库
|
|
|
|
|
*/
|
|
|
|
|
@Aspect
|
|
|
|
|
@Component
|
2025-05-03 07:03:36 +00:00
|
|
|
|
public class OperateLogAspect {
|
2025-05-03 02:20:50 +00:00
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private SysOperLogService sysOperLogService;
|
|
|
|
|
|
|
|
|
|
// 为了记录方法的执行时间
|
|
|
|
|
ThreadLocal<Long> startTime = new ThreadLocal<>();
|
|
|
|
|
|
|
|
|
|
|
2025-05-03 07:03:36 +00:00
|
|
|
|
@Before("@annotation(sysLog)")
|
|
|
|
|
public void beforeMethod(JoinPoint joinPoint, SysLog sysLog){
|
2025-05-03 02:20:50 +00:00
|
|
|
|
startTime.set(System.currentTimeMillis());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
|
|
|
|
|
* @param joinPoint 切入点
|
|
|
|
|
* @param result 返回结果
|
|
|
|
|
*/
|
2025-05-03 07:03:36 +00:00
|
|
|
|
@AfterReturning(value = "@annotation(sysLog)", returning = "result")
|
|
|
|
|
public void saveOperateLog(JoinPoint joinPoint, SysLog sysLog, Object result) {
|
2025-05-03 02:20:50 +00:00
|
|
|
|
// 获取RequestAttributes
|
|
|
|
|
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
|
|
|
|
// 从获取RequestAttributes中获取HttpServletRequest的信息
|
|
|
|
|
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
|
|
|
|
|
try {
|
|
|
|
|
// 从切面织入点处通过反射机制获取织入点处的方法
|
|
|
|
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
|
|
|
|
// 获取切入点所在的方法
|
|
|
|
|
Method method = signature.getMethod();
|
|
|
|
|
// 获取操作
|
|
|
|
|
SysOperLog sysOperLog = new SysOperLog();
|
2025-05-03 07:03:36 +00:00
|
|
|
|
sysOperLog.setTitle(sysLog.title());//设置模块名称
|
|
|
|
|
sysOperLog.setContent(sysLog.content());//设置日志内容
|
2025-05-03 02:20:50 +00:00
|
|
|
|
// 将入参转换成json
|
|
|
|
|
String params = argsArrayToString(joinPoint.getArgs());
|
|
|
|
|
// 获取请求的类名
|
|
|
|
|
String className = joinPoint.getTarget().getClass().getName();
|
|
|
|
|
// 获取请求的方法名
|
|
|
|
|
String methodName = method.getName();
|
|
|
|
|
methodName = className + "." + methodName + "()";
|
|
|
|
|
sysOperLog.setMethod(methodName); //设置请求方法
|
|
|
|
|
sysOperLog.setRequestMethod(request.getMethod());//设置请求方式
|
|
|
|
|
sysOperLog.setRequestParam(params); // 请求参数
|
|
|
|
|
sysOperLog.setResponseResult(JSON.toJSONString(result)); // 返回结果
|
|
|
|
|
// 从request中取出账号
|
|
|
|
|
String userAccount = (String) request.getAttribute("userAccount");
|
|
|
|
|
sysOperLog.setOperName(userAccount); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
|
|
|
|
|
String ip = getIp(request);
|
|
|
|
|
sysOperLog.setIp(ip); // IP地址
|
|
|
|
|
String ipLocation = getIpLocation(ip);
|
|
|
|
|
sysOperLog.setIpLocation(ipLocation); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
|
|
|
|
|
sysOperLog.setRequestUrl(request.getRequestURI()); // 请求URI
|
|
|
|
|
sysOperLog.setOperTime(new Date()); // 时间
|
|
|
|
|
sysOperLog.setStatus(0);//操作状态(0正常 1异常)
|
|
|
|
|
Long takeTime = System.currentTimeMillis() - startTime.get();//记录方法执行耗时时间(单位:毫秒)
|
|
|
|
|
sysOperLog.setTakeTime(takeTime);
|
|
|
|
|
//插入数据库
|
|
|
|
|
sysOperLogService.save(sysOperLog);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 设置操作异常切入点记录异常日志 扫描所有controller包下操作
|
|
|
|
|
* 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
|
|
|
|
|
*/
|
|
|
|
|
@AfterThrowing(pointcut = "execution(* com.greenorange.promotion.controller..*.*(..))", throwing = "e")
|
|
|
|
|
public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
|
|
|
|
|
// 获取RequestAttributes
|
|
|
|
|
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
|
|
|
|
// 从获取RequestAttributes中获取HttpServletRequest的信息
|
|
|
|
|
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
|
|
|
|
|
|
|
|
|
|
SysOperLog sysOperLog = new SysOperLog();
|
|
|
|
|
try {
|
|
|
|
|
// 从切面织入点处通过反射机制获取织入点处的方法
|
|
|
|
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
|
|
|
|
// 获取切入点所在的方法
|
|
|
|
|
Method method = signature.getMethod();
|
|
|
|
|
// 获取请求的类名
|
|
|
|
|
String className = joinPoint.getTarget().getClass().getName();
|
|
|
|
|
// 获取请求的方法名
|
|
|
|
|
String methodName = method.getName();
|
|
|
|
|
methodName = className + "." + methodName + "()";
|
|
|
|
|
// 获取操作
|
2025-05-03 07:03:36 +00:00
|
|
|
|
SysLog sysLog = method.getAnnotation(SysLog.class);
|
|
|
|
|
if (sysLog != null) {
|
|
|
|
|
sysOperLog.setTitle(sysLog.title());//设置模块名称
|
|
|
|
|
sysOperLog.setContent(sysLog.content());//设置日志内容
|
2025-05-03 02:20:50 +00:00
|
|
|
|
}
|
|
|
|
|
// 将入参转换成json
|
|
|
|
|
String params = argsArrayToString(joinPoint.getArgs());
|
|
|
|
|
sysOperLog.setMethod(methodName); //设置请求方法
|
|
|
|
|
sysOperLog.setRequestMethod(request.getMethod());//设置请求方式
|
|
|
|
|
sysOperLog.setRequestParam(params); // 请求参数
|
|
|
|
|
// 从request中取出账号
|
|
|
|
|
String userAccount = (String) request.getAttribute("userAccount");
|
|
|
|
|
sysOperLog.setOperName(userAccount); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
|
|
|
|
|
String ip = getIp(request);
|
|
|
|
|
sysOperLog.setIp(ip); // IP地址
|
|
|
|
|
String ipLocation = getIpLocation(ip);
|
|
|
|
|
sysOperLog.setIpLocation(ipLocation); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
|
|
|
|
|
sysOperLog.setRequestUrl(request.getRequestURI()); // 请求URI
|
|
|
|
|
sysOperLog.setOperTime(new Date()); // 时间
|
|
|
|
|
sysOperLog.setStatus(1);//操作状态(0正常 1异常)
|
|
|
|
|
sysOperLog.setErrorMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));//记录异常信息
|
|
|
|
|
//插入数据库
|
|
|
|
|
sysOperLogService.save(sysOperLog);
|
|
|
|
|
} catch (Exception e2) {
|
|
|
|
|
e2.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 转换异常信息为字符串
|
|
|
|
|
*/
|
|
|
|
|
public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
|
|
|
|
|
StringBuffer strbuff = new StringBuffer();
|
|
|
|
|
for (StackTraceElement stet : elements) {
|
|
|
|
|
strbuff.append(stet + "\n");
|
|
|
|
|
}
|
|
|
|
|
String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
|
|
|
|
|
message = substring(message,0 ,2000);
|
|
|
|
|
return message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 参数拼装
|
|
|
|
|
*/
|
|
|
|
|
private String argsArrayToString(Object[] paramsArray)
|
|
|
|
|
{
|
|
|
|
|
String params = "";
|
|
|
|
|
if (paramsArray != null && paramsArray.length > 0) {
|
|
|
|
|
for (Object o : paramsArray) {
|
|
|
|
|
if (o != null) {
|
|
|
|
|
try {
|
|
|
|
|
Object jsonObj = JSON.toJSON(o);
|
|
|
|
|
params += jsonObj.toString() + " ";
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return params.trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//字符串截取
|
2025-05-03 07:03:36 +00:00
|
|
|
|
public String substring(String str, int start, int end) {
|
2025-05-03 02:20:50 +00:00
|
|
|
|
if (str == null) {
|
|
|
|
|
return null;
|
|
|
|
|
} else {
|
|
|
|
|
if (end < 0) {
|
|
|
|
|
end += str.length();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (start < 0) {
|
|
|
|
|
start += str.length();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (end > str.length()) {
|
|
|
|
|
end = str.length();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (start > end) {
|
|
|
|
|
return "";
|
|
|
|
|
} else {
|
|
|
|
|
if (start < 0) {
|
|
|
|
|
start = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (end < 0) {
|
|
|
|
|
end = 0;
|
|
|
|
|
}
|
|
|
|
|
return str.substring(start, end);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 转换request 请求参数
|
|
|
|
|
* @param paramMap request获取的参数数组
|
|
|
|
|
*/
|
2025-05-03 07:03:36 +00:00
|
|
|
|
public Map<String, String> convertMap(Map<String, String[]> paramMap) {
|
2025-05-03 02:20:50 +00:00
|
|
|
|
Map<String, String> returnMap = new HashMap<>();
|
|
|
|
|
for (String key : paramMap.keySet()) {
|
|
|
|
|
returnMap.put(key, paramMap.get(key)[0]);
|
|
|
|
|
}
|
|
|
|
|
return returnMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//根据HttpServletRequest获取访问者的IP地址
|
|
|
|
|
public String getIp(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.getHeader("HTTP_CLIENT_IP");
|
|
|
|
|
}
|
|
|
|
|
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
|
|
|
|
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
|
|
|
|
|
}
|
|
|
|
|
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
|
|
|
|
ip = request.getRemoteAddr();
|
|
|
|
|
}
|
|
|
|
|
return ip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String getIpLocation(String ip) {
|
|
|
|
|
try {
|
|
|
|
|
// 发送请求到ip-api服务
|
|
|
|
|
String url = "http://ip-api.com/json/" + ip + "?lang=zh-CN"; // 获取中文结果
|
|
|
|
|
URL obj = new URL(url);
|
|
|
|
|
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
|
|
|
|
con.setRequestMethod("GET");
|
|
|
|
|
|
|
|
|
|
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
|
|
|
|
String inputLine;
|
|
|
|
|
StringBuffer response = new StringBuffer();
|
|
|
|
|
|
|
|
|
|
while ((inputLine = in.readLine()) != null) {
|
|
|
|
|
response.append(inputLine);
|
|
|
|
|
}
|
|
|
|
|
in.close();
|
|
|
|
|
|
|
|
|
|
// 解析JSON返回结果
|
|
|
|
|
JSONObject jsonResponse = JSONObject.parseObject(response.toString());
|
|
|
|
|
String region = jsonResponse.getString("regionName"); // 省
|
|
|
|
|
String city = jsonResponse.getString("city"); // 城市
|
|
|
|
|
String country = jsonResponse.getString("country"); // 国家
|
|
|
|
|
|
|
|
|
|
return city + ", " + region + ", " + country; // 返回位置
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
return "未知";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|