285 lines
12 KiB
Java
285 lines
12 KiB
Java
package com.greenorange.promotion.aop;
|
||
|
||
import com.alibaba.fastjson.JSON;
|
||
import com.alibaba.fastjson.JSONObject;
|
||
import com.greenorange.promotion.annotation.SysLog;
|
||
import com.greenorange.promotion.model.dto.fileInfo.UploadFileRequest;
|
||
import com.greenorange.promotion.model.entity.SysOperLog;
|
||
import com.greenorange.promotion.service.log.SysOperLogService;
|
||
import jakarta.annotation.Resource;
|
||
import jakarta.servlet.http.HttpServletRequest;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
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.IOException;
|
||
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
|
||
@Slf4j
|
||
public class OperateLogAspect {
|
||
|
||
@Resource
|
||
private SysOperLogService sysOperLogService;
|
||
|
||
// 为了记录方法的执行时间
|
||
ThreadLocal<Long> startTime = new ThreadLocal<>();
|
||
|
||
|
||
@Before("@annotation(sysLog)")
|
||
public void beforeMethod(JoinPoint joinPoint, SysLog sysLog){
|
||
startTime.set(System.currentTimeMillis());
|
||
}
|
||
|
||
|
||
/**
|
||
* 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
|
||
* @param joinPoint 切入点
|
||
* @param result 返回结果
|
||
*/
|
||
@AfterReturning(value = "@annotation(sysLog)", returning = "result")
|
||
public void saveOperateLog(JoinPoint joinPoint, SysLog sysLog, Object result) {
|
||
// 获取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();
|
||
sysOperLog.setTitle(sysLog.title());//设置模块名称
|
||
sysOperLog.setContent(sysLog.content());//设置日志内容
|
||
// 将入参转换成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 + "()";
|
||
// 获取操作
|
||
SysLog sysLog = method.getAnnotation(SysLog.class);
|
||
if (sysLog != null) {
|
||
sysOperLog.setTitle(sysLog.title());//设置模块名称
|
||
sysOperLog.setContent(sysLog.content());//设置日志内容
|
||
}
|
||
// 将入参转换成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();
|
||
log.warn("JSON参数解析出现异常");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return params.trim();
|
||
}
|
||
|
||
//字符串截取
|
||
public String substring(String str, int start, int end) {
|
||
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获取的参数数组
|
||
*/
|
||
public Map<String, String> convertMap(Map<String, String[]> paramMap) {
|
||
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 country = jsonResponse.getString("country"); // 国家
|
||
// String region = jsonResponse.getString("regionName"); // 省
|
||
// String city = jsonResponse.getString("city"); // 城市
|
||
//
|
||
// return country + "-" + region + "-" + city; // 返回位置
|
||
// } catch (Exception e) {
|
||
// e.printStackTrace();
|
||
// }
|
||
return "未知";
|
||
}
|
||
|
||
} |