Spring AOP +自定义注解 + Spel表达式 实现审计日志
1-简介
- 审计日记就是记录用户的操作记录
- 基于AOP动态代理 实现自定义审计日志注解, 并支持Spel表达式解析
2-实现
2-1 日志存储实体类
@Data @Builder @ToString public class AuditingLog { private String userId; // 用户id private String userNickname; //用户昵称 private String operationInfo; //操作信息 private String interfaceName; // 调用的接口方法名 private String applicationName; // 调用的服务名 private LocalDateTime createTime; //操作时间 }
2-2 自定义审计日志注解
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface AuditLog { String logInfo(); //日志信息 }
2-3 日志注解的AOP的切面
@Aspect @Component public class AuditLogAOP { @Value("${spring.application.name}") private String applicationName; //从配置文件获得服务名 // spel表达式解析器 private SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); // 参数名发现器 private DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); @Before(value = "@annotation(enableAuditLog) || @within(enableAuditLog)") public void getAutiLogInfo(JoinPoint joinPoint, AuditLog enableAuditLog){ MethodSignature signature = (MethodSignature) joinPoint.getSignature(); if (enableAuditLog == null) { enableAuditLog = signature.getMethod().getAnnotation(AuditLog.class); } // 构建日志存储对象 AuditingLog auditlog = AuditingLog.builder().applicationName(applicationName).createTime(LocalDateTime.now()).build(); auditlog.setUserId(xxx); // 从上下文获取当前操作的用户信息 auditlog.setUserNickname(xx); // 设置操作的接口方法名 auditlog.setInterfaceName(signature.getDeclaringTypeName()+"."+signature.getName()); // 获得日志注解上自定义的日志信息 String logInfo = enableAuditLog.logInfo(); // Spel表达式解析日志信息 // 获得方法参数名数组 String[] parameterNames = parameterNameDiscoverer.getParameterNames(signature.getMethod()); if (parameterNames != null && parameterNames.length > 0){ EvaluationContext context = new StandardEvaluationContext(); //获取方法参数值 Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { context.setVariable(parameterNames[i],args[i]); // 替换spel里的变量值为实际值, 比如 #user --> user对象 } // 解析出实际的日志信息 String opeationInfo = spelExpressionParser.parseExpression(logInfo).getValue(context).toString(); auditlog.setOperationInfo(opeationInfo); } // 打印日志信息 log.info(auditlog.toString()); //TODO 这时可以将日志信息auditlog进行异步存储,比如写入到文件通过logstash增量的同步到Elasticsearch或者DB } }
2-4 开启审计日志功能
- 在分布式项目中一般会将日志抽离出来公共调用, 所以为了方便的注入审计日志功能,可以编写对应 Enable注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import({AuditLogAOP.class}) // 注入AOP切面到容器 public @interface EnableAuditLog { }
3 使用
3-1 开启审计日志功能
- 在要使用审计日志功能的服务的入口类开启审计日志功能
比如
@SpringBootApplication @EnableDiscoveryClient @EnableAuditLog //开启审计日志 public class UmsAdminApplication { public static void main(String[] args) { SpringApplication.run(UmsAdminApplication.class,args); } }
3-2 在接口上使用
比如:
@AuditLog(logInfo = "'新增管理员:'+ #user.username") @PostMapping public String addUser(@RequestBody User user){ return null; }
转载:https://blog.csdn.net/weixin_41347419/article/details/107573038