Spring AOP 操作日誌實現

一、註解

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;

/**
 * 日誌註解類
 * 使用方式 @Log(value="某某接口方法")  @Log(ignore=true)
 * @author nick
 */
@Documented
@Target(ElementType.METHOD) //只能在方法上使用此註解
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {

    /**
     * 日誌描述,這裏使用了@AliasFor 別名:spring提供的
     * @return
     */
    @AliasFor("value")
    String value() default "";

    /**
     * 是否不記錄日誌
     * @return
     */
    boolean ignore() default false;

}

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.Value;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
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;
import java.util.Map;

/**
 * @author nick
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Value("${cookie.encrypt.key}")
    private String cookieEncryptKey;


    /**
     * 設置切入點
     */
    @Pointcut("@annotation(com.citydo.logging.annotation.Log)")
    public void pointcut() { }

    /**
     * 切面方法,記錄日誌
     * @return
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point){
        Object result = null;
        long beginTime = System.currentTimeMillis();
        try {
            // 執行方法
            result = point.proceed();
        } catch (Throwable e) {
            log.error("執行記錄日誌異常:{}",e.getMessage());
        }
        Signature signature = point.getSignature();
        if(!(signature instanceof MethodSignature)) {
            throw new IllegalArgumentException("暫不支持非方法註解");
        }
        //獲取執行的方法
        MethodSignature methodSign = (MethodSignature) signature;
        Method method = methodSign.getMethod();
        //判斷是否包含了 無需記錄日誌的方法
        Log logAnne = AnnotationUtils.getAnnotation(method, Log.class);
        if(logAnne != null && logAnne.ignore()) {
            return result;
        }
        // 執行時長(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        // 保存日誌
        saveSystemLog(point, time);
        return result;
    }

    /**
     * 獲取需要保存的參數
     * @param joinPoint
     * @param time
     */
    private void saveSystemLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SystemLog systemLog = new SystemLog();
        Log logAnnotation = method.getAnnotation(Log.class);
        if (logAnnotation != null) {
            // 註解上的描述 可以詳細描述
            systemLog.setOperation(logAnnotation.value());
        }
        // 方法名獲取
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        // 請求的方法參數值
        Object[] args = joinPoint.getArgs();
        // 請求的方法參數名稱
        LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNames = localVariableTableParameterNameDiscoverer.getParameterNames(method);
        if (args != null && paramNames != null) {
            String params = "";
            for (int i = 0; i < args.length; i++) {
                params += "  " + paramNames[i] + ": " + args[i];
            }
            systemLog.setParams(params);
        }
        //獲取request
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        //利用RequestContextHolder獲取requst對象
        ServletRequestAttributes requestAttr = (ServletRequestAttributes)          RequestContextHolder.currentRequestAttributes();
        // 獲取url
        String url = requestAttr.getRequest().getRequestURI();
        // 設置IP地址
        systemLog.setTime(time);
        systemLog.setMethod(className + "." + methodName + "()");
        systemLog.setIp(IpUtils.getIpAddr(request));
        systemLog.setUrl(url);
        systemLog.setOperationModule(null);
        systemLog.setOperationPage(null);
        systemLog.setOperationContent(null);
        systemLog.setOperationType(null);
        systemLog.setBeforeOperation(null);
        systemLog.setAfterOperation(null);
        systemLog.setCreateTime(System.currentTimeMillis());
        systemLog.setUpdateTime(System.currentTimeMillis());
        systemLog.setDeleteType(0);
        // 保存系統日誌
        //sysLogDao.saveSysLog(sysLog);
    }

}

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.Date;

/**
 * @author nick
 */
@Slf4j
@Data
public class SystemLog implements Serializable {

    private static final long serialVersionUID = 215831501598634496L;

    /**
     * 主鍵
     */
    private Long id;

    /**
     * 操作
     */
    private String operation;

    /**
     * 操作時間
     */
    private Long time;

    /**
     * 方法
     */
    private String method;

    /**
     * 參數
     */
    private String params;

    /**
     * ip
     */
    private String ip;

    /**
     * url
     */
    private String  url;

    /**
     * 模塊
     */
    private String operationModule;
    /**
     * 頁面 /子頁面
     */
    private String operationPage;

    /**
     * 操作內容
     */
     private String operationContent;

    /**
     * 操作類型  1--新增、2--更改、3--刪除、0---其他
     */
     private Integer operationType;

    /**
     * 操作之前的值 前一條一後一條對應
     */
     private String beforeOperation;

    /**
     * 操作之後的值 前一條一後一條對應
     */
    private String afterOperation;

    /**
     * 創建時間
     */
    private Long createTime;

    /**
     * 更新時間
     */
    private Long updateTime;

    /**
     * 刪除
     */
    private Integer deleteType;

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章