基于Spring+Aop实现的全局日志(选择性打印日志记录日志)

本文介绍了如何利用Spring AOP实现一个选择性打印和记录日志的系统,包括自定义注解、切面处理和日志级别。通过在方法上添加注解,可以控制哪些参数和返回结果需要被记录,同时提供了日志插入数据库的实现。
摘要由CSDN通过智能技术生成

基于Spring+Aop实现的全局日志功能(选择性打印日志记录日志)

前言

这是个人在优化项目老代码的一些学习记录,也希望能给各位有需要的大佬提供一种思路,SpringBoot同理

  1. 首先得导入相关依赖
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
		</dependency>

这里我使用的版本是4.2.5.RELEASE的版本

下面开始上代码

2.自定义注解

/**
 * 日志输出注解
 * 1.标注在参数上
 * @author ex_gongzhihua
 */
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggerOut {
}
/**
 * 日志处理注解标注在方法上,扫描方法的入参和出参
 * @author ex_gongzhihua
 */
@Target({ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogHandler {
}
  1. 枚举类
/**
 * 日志级别
 * @author ex_gongzhihua
 */
public enum LoggerLevel {
    INFO,
    DEBUG,
    WARN,
    ERROR
}
  1. 切面实现
/**
 * 日志切面
 * @author ex_gongzhihua
 */
@Aspect
@Component
public class LogAspect {
    private final Logger log = LoggerFactory.getLogger(LogAspect.class);
    private static final String RETURN_ERROR_PARAM = "数据校验失败";
    private static final String RETURN_ERROR_EX = "调用接口失败";

    @Autowired
    private ParameterUtil parameterUtil;

    @Autowired
    private IAiLogService aiLogService;


    /**
     * 通用日志代码
     */
    private void commonLogCode(int aiType, String businessType, long startTime, String responseResult, String result, String userName, String businessScenario, String channelSource) {
        long endTime = System.currentTimeMillis();
        insertAiLog(aiType, businessType, startTime, endTime, responseResult, (null != result && result.length() >= 1800) ? result.substring(0, 1800) : result, userName, businessScenario, channelSource);
    }

    /**
     * 匹配所有带LogHandler注解的方法
     */
    @Pointcut("execution(@com.axatp.common.annotation.LogHandler * * (..))")
    public void resultLog(){

    }

    @Around(value = "resultLog()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        long startTime = 0;
        String responseResult= TableStatusEnum.SUCCESS.getStatusName();
        MethodSignature signature=(MethodSignature) point.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        LogHandler logHandler = method.getAnnotation(LogHandler.class);
        if (logHandler==null){
            return point.proceed();
        }
        //获取请求的类名
        String className=point.getTarget().getClass().getName();
        Object result=null;
        //获取请求的方法名
        String methodName = method.getName();
        try {
            //方法执行前入参打印
            before(point,signature,method,className,methodName);
            startTime=System.currentTimeMillis();
            result=point.proceed();
        }catch (BussinessException e){
            printLog(LoggerLevel.ERROR,RETURN_ERROR_PARAM,e.getMessage());
            responseResult = TableStatusEnum.PARAMETER_ERROR.getStatusName();
        }catch (Exception e) {
            printLog(LoggerLevel.ERROR,RETURN_ERROR_EX,e.getMessage());
            responseResult = TableStatusEnum.FAIL.getStatusName();
        } finally {
            after(point,signature,method,className,methodName,result,responseResult,startTime);
        }
        return result;
    }

    /**
     * 方法执行前,入参打印
     * @param point 切面对象
     * @param signature 署名信息对象
     * @param method  切入点方法
     * @param className 切入点类名
     * @param methodName 切入点方法名
     */
    public void before(JoinPoint point, MethodSignature signature, Method method, String className, String methodName) throws BussinessException{
        String userName="";
        String password="";
        String channelSource="";
        String businessScenario="";
        Object[] args = point.getArgs();
        String[] parameterNames = signature.getParameterNames();
        Annotation[][] annotationArr = method.getParameterAnnotations();
        for (int i = 0; i < parameterNames.length; i++) {
            Annotation[] annotations=annotationArr[i];
            LoggerOut loggerOut=null;
            for (Annotation annotation : annotations) {
                if (annotation instanceof LoggerOut){
                    loggerOut=(LoggerOut) annotation;
                    break;
                }
            }
            if (loggerOut==null){
                //未携带注解的参数不做处理
                continue;
            }
            if ("userName".equals(parameterNames[i])){
                userName=(String) args[i];
            }else if ("password".equals(parameterNames[i])){
                password=(String) args[i];
            }else if ("channelSource".equals(parameterNames[i])){
                channelSource=(String) args[i];
            }else if ("businessScenario".equals(parameterNames[i])){
                businessScenario=(String) args[i];
            }
            Object arg=args[i];
            if (arg==null){
                printLog(LoggerLevel.INFO,"className:{}===>methodName:{}-param-log====>param:{},value:{}",
                        className,methodName,parameterNames[i],null);
                continue;
            }
            printLog(LoggerLevel.INFO,"className:{}===>methodName:{}-param-log====>param:{},value:{}",
                    className,methodName,parameterNames[i],arg);
        }
        //参数校验
        parameterUtil.parameter(channelSource,businessScenario,userName,password);
    }

    /**
     *
     * @param point
     * @param signature
     * @param method
     * @param className
     * @param methodName
     * @param result
     * @param responseResult
     * @param startTime
     */
    public void after(JoinPoint point,MethodSignature signature, Method method, String className, String methodName,Object result,String responseResult,long startTime){
        String userName="";
        String channelSource="";
        String businessScenario="";
        int aiType = 0;
        Result results;
        Object[] args = point.getArgs();
        String[] parameterNames = signature.getParameterNames();
        Annotation[][] annotationArr = method.getParameterAnnotations();
        for (int i = 0; i < parameterNames.length; i++) {
            Annotation[] annotations=annotationArr[i];
            LoggerOut loggerOut=null;
            for (Annotation annotation : annotations) {
                if (annotation instanceof LoggerOut){
                    loggerOut=(LoggerOut) annotation;
                    break;
                }
            }
            if (loggerOut==null){
                //未携带注解的参数不做处理
                continue;
            }
            //根据参数名称来读取相对应参数值
            if (("userName").equals(parameterNames[i])){
                userName=(String) args[i];
            }else if ("channelSource".equals(parameterNames[i])){
                channelSource=(String) args[i];
            }else if ("businessScenario".equals(parameterNames[i])){
                businessScenario=(String) args[i];
            }else if ("aiType".equals(parameterNames[i])){
                aiType=(int)args[i];
            }
        }
            //判断执行结果类型
            if (result instanceof Result){
                results=(Result) result;
                commonLogCode(aiType,null,startTime,responseResult,JSON.toJSON(results.getData()).toString(),userName,businessScenario,channelSource);
            }else {
                if (result==null){
                    commonLogCode(aiType,null,startTime,responseResult,null,userName,businessScenario,channelSource);
                }else {
                    commonLogCode(aiType,null,startTime,responseResult,result.toString(),userName,businessScenario,channelSource);
                }
            }
    }

    /**
     * 记录日志
     *
     * @param aiType           平台类型
     * @param businessType     业务类型
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param responseResult   响应信息
     * @param responseParam    响应数据
     * @param operateUser      用户名
     * @param businessScenario 业务来源
     * @param channelSource    渠道
     */
    public void insertAiLog(int aiType, String businessType, long startTime, long endTime, String responseResult, String responseParam, String operateUser, String businessScenario, String channelSource) {
        AiLog aiLog = new AiLog();
        aiLog.setPlatformType(String.valueOf(aiType));
        aiLog.setBusinessType(businessType);
        aiLog.setTimeConsume(String.valueOf(endTime - startTime));
        aiLog.setResponseResult(responseResult);
        aiLog.setResponseParam(responseParam);
        aiLog.setCreatedBy(operateUser);
        aiLog.setUpdatedBy(operateUser);
        aiLog.setBusinessScenario(businessScenario);
        aiLog.setChannelSource(channelSource);
        aiLogService.addAiLog(aiLog);
    }


    /**
     * 根据日志级别打印不同的日志参数
     */
    public void printLog(LoggerLevel loggerLevel,String formatStr,Object... format){
        if (loggerLevel== LoggerLevel.INFO){
            log.info(formatStr,format);
        }else if (loggerLevel==LoggerLevel.DEBUG){
            log.debug(formatStr,format);
        }else if (loggerLevel==LoggerLevel.ERROR){
            log.error(formatStr,format);
        }else if (loggerLevel==LoggerLevel.WARN){
            log.warn(formatStr,format);
        }
    }
}

以上数据校验以及个别常量只是我个人项目所需,大家参考思路即可
在这里插入图片描述
使用的话两个注解配合使用即可,LoggerOut标注需要打印以及记录日志的参数
代码还不够完全完善有点冗余,我是想先记录下来,大家有更好的思路欢迎指出~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值