AOP实现日志打印

package com.youmu.framework.love.interfaces;

import java.lang.annotation.*;

/**
 * @Author: guodong
 * @CreateTime: 2023-04-19  16:38
 * @Description: 自定义注解日志类
 * @Version: 1.0
 */
@Documented
@Target(ElementType.METHOD)//注解的作用类型为方法
@Retention(RetentionPolicy.RUNTIME)//注解可在运行阶段被加载到Class对象中
public @interface SysLog {

    boolean isPrint() default false;

    /**
     * 日志等级:自己定,此处分为1-9
     */
    int level() default 0;

    /**
     * 方法描述,可使用占位符获取参数:{{tel}}
     */
    String detail() default "";



}
package com.youmu.framework.love.dtos;

import lombok.Data;

import java.util.Date;

/**
 * @Author: guodong
 * @CreateTime: 2023-04-19  16:59
 * @Description: TODO
 * @Version: 1.0
 */
@Data
public class OperationLog {

    private String id;

    private Date createTime;

    /**
     * 日志等级
     */
    private Integer level;
    /**
     * 被操作的对象
     */
    private String operationUnit;
    /**
     * 方法名
     */
    private String method;
    /**
     * 参数
     */
    private String args;
    /**
     * 操作人id
     */
    private String userId;
    /**
     * 操作人
     */
    private String userName;
    /**
     * 日志描述
     */
    private String describe;
    /**
     * 操作类型
     */
    private String operationType;
    /**
     * 方法运行时间
     */
    private Long runTime;
    /**
     * 方法返回值
     */
    private String returnValue;


}
package com.youmu.framework.love.config;

import com.alibaba.fastjson.JSON;
import com.youmu.framework.love.dtos.OperationLog;
import com.youmu.framework.love.interfaces.SysLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @Author: guodong
 * @CreateTime: 2023-04-19  16:48
 * @Description: 打印日志信息
 * @Version: 1.0
 */
@Aspect
@Component
@Slf4j
public class SysLogAop {


    /**
     * 此处的切点是注解的方式,也可以用包名的方式达到相同的效果
     */
    @Pointcut("execution(* com.youmu.framework.love.controller.*.*(..))")
    public void operationLog() {
    }


    /**
     * 环绕增强,相当于MethodInterceptor
     */
    @Around("operationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object res = null;
        long time = System.currentTimeMillis();
        try {
            res = joinPoint.proceed();
            time = System.currentTimeMillis() - time;
        } catch (Exception e) {
            log.error(">> doAround error:{}", e.getMessage(), e);
        } finally {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            SysLog sysLog = signature.getMethod().getAnnotation(SysLog.class);
            if (sysLog != null && sysLog.isPrint()) {
                addOperationLog(joinPoint, res, time);
            } else {
                res = joinPoint.proceed();
            }
        }
        return res;
    }

    private void addOperationLog(JoinPoint joinPoint, Object res, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        OperationLog operationLog = new OperationLog();
        operationLog.setRunTime(time);
        operationLog.setReturnValue(JSON.toJSONString(res));
        operationLog.setId(UUID.randomUUID().toString());
        operationLog.setArgs(JSON.toJSONString(joinPoint.getArgs()));
        operationLog.setCreateTime(new Date());
        operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
        operationLog.setUserId("#{currentUserId}");
        operationLog.setUserName("#{currentUserName}");
        SysLog annotation = signature.getMethod().getAnnotation(SysLog.class);
        if (annotation != null) {
            operationLog.setLevel(annotation.level());
            operationLog.setDescribe(getDetail(((MethodSignature) joinPoint.getSignature()).getParameterNames(), joinPoint.getArgs(), annotation));
        }
        log.info(">> addOperationLog:{}", operationLog);
    }

    /**
     * 对当前登录用户和占位符处理
     *
     * @param argNames   方法参数名称数组
     * @param args       方法参数数组
     * @param annotation 注解信息
     * @return 返回处理后的描述
     */
    private String getDetail(String[] argNames, Object[] args, SysLog annotation) {
        Map<Object, Object> map = new HashMap<>();
        for (int i = 0; i < argNames.length; i++) {
            map.put(argNames[i], args[i]);
        }

        String detail = annotation.detail();
        try {
            detail = "'" + "#{currentUserName}" + "'=》" + annotation.detail();
            for (Map.Entry<Object, Object> entry : map.entrySet()) {
                Object k = entry.getKey();
                Object v = entry.getValue();
                detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return detail;
    }


}
   @SysLog(isPrint = true, level = 0, detail = "获取推荐列表")
    public ResultMessage<List<RecommendResponseVO>> getRecommendList(@RequestBody RecommendRequestVO requestVO) {
        log.info(">> getRecommendList params:{}", JSONObject.toJSONString(requestVO));
        List<RecommendResponseVO> recommendResponseVOList = Lists.newArrayList();
        String result = "";
        try {
            result = HttpUtils.postData(url, null, JSONObject.toJSONString(requestVO));
            log.info(">> getRecommendList result:{}", result);
            recommendResponseVOList = JSONObject.parseArray(result, RecommendResponseVO.class);
        } catch (Exception e) {
            log.error(">> getRecommendList error:{}", e.getMessage(), e);
        }
        return new ResultMessage<>(recommendResponseVOList);
    }

springboot项目中使用AOP实现日志打印。

 

posted @ 2023-04-19 17:32  郭慕荣  阅读(88)  评论(0编辑  收藏  举报