在開發過程中,可能會遇到需要記錄使用者操作記錄的情況,這時候可以使用Spring的AOP實作日志埋點,記錄使用者的操作行為
實作步驟:
1.日志記錄注解(使用時直接添加到需要記錄的方法上)
package com.immo.jkzs.annotation;
import com.immo.jkzs.enums.OperationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLogAnnotation {
String module() default ""; //子產品
String remark() default ""; //備注
OperationType operationType() default OperationType.UNKNOWN;//操作類型
}
2.操作類型
package com.immo.jkzs.enums;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
/**
* 操作類型(enum):主要是select,insert,update,delete
*/
@AllArgsConstructor
@Getter
public enum OperationType {
/**
* 操作類型
*/
UNKNOWN("unknown"),
DELETE("delete"),
SELECT("select"),
UPDATE("update"),
INSERT("insert");
private String value;
}
3.定義切面類
package com.immo.jkzs.aspect;
import com.immo.jkzs.annotation.OperateLogAnnotation;
import com.immo.jkzs.common.UserInfo;
import com.immo.jkzs.entity.BaseUser;
import com.immo.jkzs.entity.OperateLog;
import com.immo.jkzs.service.IOperateLogService;
import com.immo.jkzs.service.IRedisService;
import com.immo.jkzs.util.DateUtils;
import com.immo.jkzs.util.IdUtils;
import com.immo.jkzs.util.IpAddressUtil;
import com.immo.jkzs.util.StringUtils;
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.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* 使用者記錄檔
*
* @author Jonathan.WQ
*/
@Aspect
@Component
public class OperationLogAspect {
@Autowired
private IOperateLogService operateLogService;
@Pointcut("@annotation(com.immo.jkzs.annotation.OperateLogAnnotation)")
public void pointcut() {
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) {
Object result = null;
//子產品開始時間
long start = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
OperateLog operateLog = new OperateLog();
operateLog.setId(IdUtils.getInstanse().getUID());
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
// 設定請求的方法名
operateLog.setMethod(className + "." + methodName + "()");
// 請求的方法參數值
Object[] args = joinPoint.getArgs();
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = u.getParameterNames(method);
if (args != null && paramNames != null) {
StringBuilder paramsBuilder = new StringBuilder();
for (int i = 0; i < args.length; i++) {
String paramName = paramNames[i];
Object arg = args[i];
//考慮到參數過長的情況,故而截取
paramsBuilder.append(paramName).append(": ");
String paramValue = String.valueOf(arg);
if (paramValue.length() > 50) {
paramsBuilder.append(paramValue.substring(0, 50));
} else {
paramsBuilder.append(paramValue);
}
paramsBuilder.append("...");
if (i != args.length - 1) {
paramsBuilder.append(" ,");
}
}
// 設定請求的方法參數名稱
operateLog.setParameter(paramsBuilder.toString());
}
// 擷取request
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// 設定IP位址
operateLog.setIp(IpAddressUtil.getIpAddr(request));
// 擷取使用者
String authorization = request.getParameter("Authorization");
if (StringUtils.isNotNull(authorization)) {
BaseUser user = UserInfoThreadLocal.getUser();
operateLog.setUserName(user.getName());
operateLog.setUserId(user.getId());
}
//擷取系統時間
operateLog.setCreateTime(DateUtils.getCurrentDate());
OperateLogAnnotation OperateLogAnnotation = method.getAnnotation(OperateLogAnnotation.class);
if (OperateLogAnnotation != null) {
// 注解上的描述
try {
operateLog.setModule(OperateLogAnnotation.module());
operateLog.setRemark(OperateLogAnnotation.remark());
operateLog.setOperationType(OperateLogAnnotation.operationType().name());
result = joinPoint.proceed();
long end = System.currentTimeMillis();
//将計算好的時間儲存在實體中
operateLog.setResponseTime("" + (end - start));
operateLog.setCommit("success");
//儲存進資料庫
operateLogService.save(operateLog);
} catch (Throwable e) {
operateLog.setModule(OperateLogAnnotation.module());
long end = System.currentTimeMillis();
operateLog.setResponseTime("" + (end - start));
operateLog.setCommit("failed");
operateLog.setExceptionType(e.getClass().getName());
//儲存進資料庫
operateLogService.save(operateLog);
}
}
return result;
}
}
4.使用者記錄檔
package com.immo.jkzs.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 使用者操作記錄表
*
* @author Jonathan.WQ
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName("operate_log")
public class OperateLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主鍵
*/
@TableId(value = "id", type = IdType.INPUT)
private String id;//
/**
* 使用者ID
*/
@TableField("user_id")
private String userId;
/**
* 使用者昵稱
*/
@TableField("user_name")
private String userName;
/**
* 使用者類型
*/
@TableField("user_type")
private String userType;
/**
* 通路子產品
*/
@TableField("module")
private String module;
/**
* 操作類型
*/
@TableField("operation_type")
private String operationType;
/**
* 備注
*/
@TableField("remark")
private String remark;
/**
* 通路方法
*/
@TableField("method")
private String method;
/**
* 通路參數
*/
@TableField("parameter")
private String parameter;
/**
* 響應時間ms
*/
@TableField("response_time")
private String responseTime;
/**
* 建立時間
*/
@TableField("create_time")
private Date createTime;
/**
* 執行結果
*/
@TableField("commit")
private String commit;
/**
* 異常類型
*/
@TableField("exception_type")
private String exceptionType;
/**
* IP位址
*/
@TableField("ip")
private String ip;
}
5.使用注解
@OperateLogAnnotation(remark = "新增意見回報",operationType= OperationType.INSERT)
@PostMapping("/add")
public CommonResult addHandler(@RequestParam("feedBack") FeedBackDTO feedbackDTO, HttpServletRequest request) {
return feedbackService.add(feedbackDTO, request);
}