SpringAop 实现记录操作日志

2 篇文章 0 订阅
1 篇文章 0 订阅

SpringAop 实现记录操作日志


前言

系统操作日志是一个重复性的工作,直接在对应逻辑后面写也不好,后续添加也不方便,所以通过注解SpringAop的方式来实现


提示:使用的是 spring 框架

一、效果展示

在这里插入图片描述
在这里插入图片描述

这里列举几重常用的用法

 // 参数解析:<.....> 是解析模板,可自己定义   
 // args 是获取入参数里面属性值  eg: #args.对象名.属性名  或  #args.属性名
 // return 是获取返回对象的属性值  eg: #return.对象名.属性名 或  #return.属性名
 // 高级用法: HashMap<String, Object> map = new HashMap<>(); map.put("data",new UserEntity());
 // return['data'].username 获取返回值map里面的data键的值,拿到对象在获取用户名username

更多用法后面会提到

二、使用步骤

1.定义注解类

代码如下(示例): 更多参数可自行定义

	@Target({ ElementType.PARAMETER, ElementType.METHOD })
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	public @interface LogMessage {
	    /**
	     * 模块名称
	     * @return
	     */
	    String name() default "";
	    /**
	     * 操作类型
	     * @return
	     */
	    String type() default "";
	    /**
	     * 操作描述 表达式编写的地方
	     * @return
	     */
	    String desc() default "";
	}

2.定义注解解析类

代码如下(示例):

@Aspect
@Component
public class LogMessageAspect {
	// 记录日志
	private static final Logger logger = LoggerFactory.getLogger(LogMessageAspect.class);
	// 下面是区分获取返回值还是参数用的,可自行定义
    public final static String REPLACE_REGEX_ARG = "args\\.";
    public final static String MATCHES_REGEX_ARG = "(.*)"+REPLACE_REGEX_ARG+"(.*)>";
    public final static String REPLACE_REGEX_RETURN = "return";
    public final static String MATCHES_REGEX_RETURN = "(.*)"+REPLACE_REGEX_RETURN+"(.*)>";
	@AfterReturning(pointcut = "@annotation(log)", returning = "result")
    public void doAfterReturning(JoinPoint point, LogMessage log, Object result){
        //拿到写表达式的参数
        String desc = log.desc();
        EvaluationContext context = new StandardEvaluationContext();
        if (StringUtils.isEmpty(log.desc())){
            return;
        }
        // 获取参数执行逻辑
        if (log.desc().matches(MATCHES_REGEX_ARG)){
            desc = desc.replaceAll(REPLACE_REGEX_ARG,"");
            Object[] args = point.getArgs();
            Method method = ((MethodSignature) point.getSignature()).getMethod();
            ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
            String[] params = parameterNameDiscoverer.getParameterNames(method);
            for (int i = 0; i < Objects.requireNonNull(params).length; i++) {
                context.setVariable(params[i], args[i]);
            }
        }
        // 获取返回值执行逻辑
        if (log.desc().matches(MATCHES_REGEX_RETURN)) {
            context.setVariable(REPLACE_REGEX_RETURN,result);
        }
        // 创建解析器解析方法 可定义  
        //ParserContext parserContext = new TemplateParserContext("{", "}");
        ParserContext parserContext = new TemplateParserContext("<", ">");
        //创建解析器
        SpelExpressionParser parser = new SpelExpressionParser();
        // 这里是为了解析失败不影响正常接口逻辑
        Object value = null;
        try {
            value = parser.parseExpression(desc,parserContext).getValue(context);
        } catch (Exception e) {
            logger.error("日志记录异常 {}",e.getMessage());
        }
        
        // dosomething 我这里简单打印下,可以插入到数据库
        //User user = SUtils.getLoginUser();
        logger.info("操作模块 {}",log.name());
        logger.info("操作类型 {}",log.type());
        // 这一步请根据自己框架获取当前操作人信息
        logger.info("操作人 {}",user.getName());
        logger.info("操作方法 {}",point.getSignature().getName() + "()");
        // 可以插入更多参数,这里不做过多阐述 IP,浏览器类型 等
        // saveLog
        
    }
}

打印详情
请添加图片描述

3.在接口上使用注解

@RestController
@RequestMapping("/test")
public class TestController{
	@LogMessage(name = "用户管理" , desc = "新增用户:<#args.user.username>",type = "INSERT")
    @PostMapping("/save")
    public AjaxResult save(UserEntity user)
    {
        return AjaxResult.success(...);
    }
    // 实例对象
	class UserEntity {
	    private Integer userId;
	    private String username;
	    //setter
	    //getter
	}
}

总结

做完上面两步,就可以简单的记录操作日志了,我们可以把操作日志插入到数据库中
这里使用的spring 的技术 SpEL ,表达式功能很强大,还能做if判断,基本满足你写日志的要求,更多用法请搜索

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值