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;

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