SpringAop 实现记录操作日志
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判断,基本满足你写日志的要求,更多用法请搜索
上一篇:
多线程四大经典案例
下一篇:
批量导出Excel并压缩zip