refactor: 日志模块

V0.5.x
regan 2023-05-19 00:45:38 +08:00
parent d7a4f0228d
commit 6da2c1de6e
7 changed files with 534 additions and 0 deletions

View File

@ -0,0 +1,48 @@
package cc.iotkit.common.log.annotation;
import cc.iotkit.common.log.enums.BusinessType;
import cc.iotkit.common.log.enums.OperatorType;
import java.lang.annotation.*;
/**
*
*
* @author ruoyi
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
*
*/
String title() default "";
/**
*
*/
BusinessType businessType() default BusinessType.OTHER;
/**
*
*/
OperatorType operatorType() default OperatorType.MANAGE;
/**
*
*/
boolean isSaveRequestData() default true;
/**
*
*/
boolean isSaveResponseData() default true;
/**
*
*/
String[] excludeParamNames() default {};
}

View File

@ -0,0 +1,220 @@
package cc.iotkit.common.log.aspect;
import cc.iotkit.common.log.annotation.Log;
import cc.iotkit.common.log.enums.BusinessStatus;
import cc.iotkit.common.log.event.OperLogEvent;
import cc.iotkit.common.satoken.utils.LoginHelper;
import cc.iotkit.common.utils.JsonUtils;
import cc.iotkit.common.utils.SpringUtils;
import cc.iotkit.common.utils.StringUtils;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.http.HttpMethod;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import java.util.Collection;
import java.util.Map;
/**
*
*
* @author Lion Li
*/
@Slf4j
@Aspect
@AutoConfiguration
public class LogAspect {
/**
*
*/
public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
/**
*
*/
private static final ThreadLocal<StopWatch> TIME_THREADLOCAL = new TransmittableThreadLocal<>();
/**
*
*/
@Before(value = "@annotation(controllerLog)")
public void boBefore(JoinPoint joinPoint, Log controllerLog) {
StopWatch stopWatch = new StopWatch();
TIME_THREADLOCAL.set(stopWatch);
stopWatch.start();
}
/**
*
*
* @param joinPoint
*/
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
handleLog(joinPoint, controllerLog, null, jsonResult);
}
/**
*
*
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
handleLog(joinPoint, controllerLog, e, null);
}
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
try {
// *========数据库日志=========*//
OperLogEvent operLog = new OperLogEvent();
operLog.setTenantId(LoginHelper.getTenantId());
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
String ip = ServletUtils.getClientIP();
operLog.setOperIp(ip);
operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
operLog.setOperName(LoginHelper.getUsername());
if (e != null) {
operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
operLog.setMethod(className + "." + methodName + "()");
// 设置请求方式
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 设置消耗时间
StopWatch stopWatch = TIME_THREADLOCAL.get();
stopWatch.stop();
operLog.setCostTime(stopWatch.getTime());
// 发布事件保存数据库
SpringUtils.context().publishEvent(operLog);
} catch (Exception exp) {
// 记录本地异常日志
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
} finally {
TIME_THREADLOCAL.remove();
}
}
/**
* Controller
*
* @param log
* @param operLog
* @throws Exception
*/
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception {
// 设置action动作
operLog.setBusinessType(log.businessType().ordinal());
// 设置标题
operLog.setTitle(log.title());
// 设置操作人类别
operLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request参数和值
if (log.isSaveRequestData()) {
// 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog, log.excludeParamNames());
}
// 是否需要保存response参数和值
if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) {
operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000));
}
}
/**
* log
*
* @param operLog
* @throws Exception
*/
private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod();
if (MapUtil.isEmpty(paramsMap)
&& HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
} else {
MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES);
MapUtil.removeAny(paramsMap, excludeParamNames);
operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000));
}
}
/**
*
*/
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
StringBuilder params = new StringBuilder();
if (paramsArray != null && paramsArray.length > 0) {
for (Object o : paramsArray) {
if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
try {
String str = JsonUtils.toJsonString(o);
Dict dict = JsonUtils.parseMap(str);
if (MapUtil.isNotEmpty(dict)) {
MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);
MapUtil.removeAny(dict, excludeParamNames);
str = JsonUtils.toJsonString(dict);
}
params.append(str).append(" ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return params.toString().trim();
}
/**
*
*
* @param o
* @return truefalse
*/
@SuppressWarnings("rawtypes")
public boolean isFilterObject(final Object o) {
Class<?> clazz = o.getClass();
if (clazz.isArray()) {
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
} else if (Collection.class.isAssignableFrom(clazz)) {
Collection collection = (Collection) o;
for (Object value : collection) {
return value instanceof MultipartFile;
}
} else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) o;
for (Object value : map.entrySet()) {
Map.Entry entry = (Map.Entry) value;
return entry.getValue() instanceof MultipartFile;
}
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
|| o instanceof BindingResult;
}
}

View File

@ -0,0 +1,18 @@
package cc.iotkit.common.log.enums;
/**
*
*
* @author ruoyi
*/
public enum BusinessStatus {
/**
*
*/
SUCCESS,
/**
*
*/
FAIL,
}

View File

@ -0,0 +1,58 @@
package cc.iotkit.common.log.enums;
/**
*
*
* @author ruoyi
*/
public enum BusinessType {
/**
*
*/
OTHER,
/**
*
*/
INSERT,
/**
*
*/
UPDATE,
/**
*
*/
DELETE,
/**
*
*/
GRANT,
/**
*
*/
EXPORT,
/**
*
*/
IMPORT,
/**
* 退
*/
FORCE,
/**
*
*/
GENCODE,
/**
*
*/
CLEAN,
}

View File

@ -0,0 +1,23 @@
package cc.iotkit.common.log.enums;
/**
*
*
* @author ruoyi
*/
public enum OperatorType {
/**
*
*/
OTHER,
/**
*
*/
MANAGE,
/**
*
*/
MOBILE
}

View File

@ -0,0 +1,52 @@
package cc.iotkit.common.log.event;
import lombok.Data;
import jakarta.servlet.http.HttpServletRequest;
import java.io.Serial;
import java.io.Serializable;
/**
*
*
* @author Lion Li
*/
@Data
public class LogininforEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
private String tenantId;
/**
*
*/
private String username;
/**
* 0 1
*/
private String status;
/**
*
*/
private String message;
/**
*
*/
private HttpServletRequest request;
/**
*
*/
private Object[] args;
}

View File

@ -0,0 +1,115 @@
package cc.iotkit.common.log.event;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
*
*
* @author Lion Li
*/
@Data
public class OperLogEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
private Long operId;
/**
* ID
*/
private String tenantId;
/**
*
*/
private String title;
/**
* 0 1 2 3
*/
private Integer businessType;
/**
*
*/
private Integer[] businessTypes;
/**
*
*/
private String method;
/**
*
*/
private String requestMethod;
/**
* 0 1 2
*/
private Integer operatorType;
/**
*
*/
private String operName;
/**
*
*/
private String deptName;
/**
* url
*/
private String operUrl;
/**
*
*/
private String operIp;
/**
*
*/
private String operLocation;
/**
*
*/
private String operParam;
/**
*
*/
private String jsonResult;
/**
* 0 1
*/
private Integer status;
/**
*
*/
private String errorMsg;
/**
*
*/
private Date operTime;
/**
*
*/
private Long costTime;
}