自定义注解实现记录日志功能(注解支持SpEL表达式)

文章介绍了如何创建一个Java接口用于定义操作日志注解,以及如何使用SpringAOP实现对带有该注解的方法进行前置、后置和异常处理,包括SpEL表达式用于动态获取参数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、首先创建个接口类Log


import java.lang.annotation.*;

/**
 * @description: 自定义操作日志记录注解
 * @author xizc
 *
 */
@Target({ ElementType.PARAMETER, ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Log {
    /**
     * 日志类别
     */
    public LogType logType();

    /**
     * 操作类别
     */
    public BusinessType businessType();

    /**
     * 关联Id
     */
    public String businessId();

    /**
     * 内容
     */
    public String content();

}

二、编写切面类


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 
 * @description: 操作日志记录处理
 * @author xizc
 */
@Aspect
@Component
public class LogAspect {
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    /**
     * 获取被拦截方法参数名列表(使用Spring支持类库)
     */
    LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
    ExpressionParser parser = new SpelExpressionParser();

    /**
     * 处理请求前执行
     * @param joinPoint 切点
     */
    @Before(value = "@annotation(methodLog)")
    public void boBefore(JoinPoint joinPoint, Log methodLog) {
        handleLog(joinPoint, methodLog, null, null);
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(methodLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log methodLog, Object jsonResult) {
        handleLog(joinPoint, methodLog, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "@annotation(methodLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log methodLog, Exception e) {
        handleLog(joinPoint, methodLog, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, Log methodLog, final Exception e, Object jsonResult) {
        try {
            Object[] args = joinPoint.getArgs();
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            String[] params = discoverer.getParameterNames(method);
            EvaluationContext context = new StandardEvaluationContext();
            for (int len = 0; len < params.length; len++) {
                context.setVariable(params[len], args[len]);
            }

            //解析businessId注解值中的SpEL表达式
            String businessIdSpel = methodLog.businessId();
            Expression businessIdExpression = parser.parseExpression(businessIdSpel);
            String businessId = businessIdExpression.getValue(context, String.class);
            System.out.println("businessId:"+ businessId);

            //解析content注解值中的SpEL表达式
            String contentSpel = methodLog.content();
            Expression contentExpression = parser.parseExpression(contentSpel);
            String content = contentExpression.getValue(context, String.class);
            System.out.println("content:"+ content);
            
            //到此已经解析并获取到注解里面的信息,下面可以根据自己的业务相应的逻辑

        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }
}

根据自己情况来删减切入点。

SpEL表达式可以获取入参对象里面的属性,例如传入User对象user里面的username,那么SpEL表达式就是 #user.username 。

三、测试

在controller里面写个方法

 /**
     * 测试log注解
     *
     * @param ids
     * @param msg
     */
    @GetMapping("/test5")
    @Log(logType = LogType.EQUIP, businessType = BusinessType.EXPORT, businessId = "#ids", content = "'测试拼接参数'+#msg")
    public void test5(Long[] ids, String msg) {

    }

然后请求接口:

打印结果如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值