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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM