用aop实现登陆日志、和操作日志持久化

用aop实现登陆日志、和操作日志持久化

在 Java 中,可以使用 AOP(Aspect-Oriented Programming)来实现登录日志操作日志持久化功能。通过 AOP,我们可以将日志记录这类 **横切关注点(cross-cutting concerns)**从业务逻辑中分离出来,实现更好的代码结构和可维护性。下面是一个简单的示例代码,演示如何使用 AOP 在登录和操作时记录日志并将日志持久化到数据库中。

  1. 定义日志实体类

    首先定义登录日志和操作日志的实体类,包括相关的字段,如用户名、登录时间、操作内容、操作时间等。
    
    public class LoginLog {
        private String username;
        private Date loginTime;
        // 省略其他字段和getter/setter方法
    }
    
    public class OperationLog {
        private String username;
        private String operation;
        private Date operationTime;
        // 省略其他字段和getter/setter方法
    }
    
  2. 编写持久化层(DAO)

    编写持久化层的代码,负责将日志数据存储到数据库中。

    public interface LogDao {
        void saveLoginLog(LoginLog loginLog);
        void saveOperationLog(OperationLog operationLog);
    }
    
    public class LogDaoImpl implements LogDao {
        // 实现持久化方法
          @Override
        public void saveLoginLog(LoginLog loginLog) {
            // 将登录日志信息保存到数据库中的具体实现代码
            System.out.println("Saving login log to the database: " + loginLog);
        }
    
        @Override
        public void saveOperationLog(OperationLog operationLog) {
            // 将操作日志信息保存到数据库中的具体实现代码
            System.out.println("Saving operation log to the database: " + operationLog);
        }
    }
    
  3. 编写AOP切面

    编写AOP切面,定义切点和通知,用于捕获登录和操作的相关行为,并在切点处插入通知以实现日志记录。

    @Aspect
    @Component
    public class LogAspect {
    
        @Autowired
        private LogDao logDao;
    
        // 登录切点
        @Pointcut("execution(* com.example.service.UserService.login(..))")
        public void loginPointcut() {}
    
        // 操作切点
        @Pointcut("execution(* com.example.service.*Service.*(..))")
        public void operationPointcut() {}
    
        // 登录日志通知
        @AfterReturning(pointcut = "loginPointcut()", returning = "result")
        public void logLogin(JoinPoint joinPoint, Object result) {
            String username = (String) joinPoint.getArgs()[0];
            LoginLog loginLog = new LoginLog();
            loginLog.setUsername(username);
            loginLog.setLoginTime(new Date());
            logDao.saveLoginLog(loginLog);
        }
        注解:
        这段代码使用了 @AfterReturning 注解来定义一个通知方法 logLogin,该方法在切点 loginPointcut() 匹配的目标方法正常返回后执行。下面是对这段代码的详细解释:
    
    @AfterReturning(pointcut = "loginPointcut()", returning = "result"):使用 @AfterReturning 注解表示定义的是一个返回通知,在切点 loginPointcut() 匹配的方法正常返回后执行,returning 属性指定了方法返回值将被传递给通知方法的参数。
    
    public void logLogin(JoinPoint joinPoint, Object result):logLogin 方法接收两个参数,一个是 JoinPoint 对象,提供了关于连接点(即目标方法)的信息;另一个是方法的返回值,即 result 对象。
    
    String username = (String) joinPoint.getArgs()[0];:通过 joinPoint 对象的 getArgs() 方法获取目标方法的参数数组,然后取第一个参数作为用户名,并强制转换为字符串类型赋值给 username 变量。
    
    LoginLog loginLog = new LoginLog();:创建一个 LoginLog 对象,用于存储登录日志信息。
    
    loginLog.setUsername(username);:将用户名设置到 LoginLog 对象中。
    
    loginLog.setLoginTime(new Date());:设置登录时间为当前时间。
    
    logDao.saveLoginLog(loginLog);:调用 logDao 对象的 saveLoginLog 方法保存登录日志信息到数据库。
    
    -----------------------------------------------------------------------------------------------
        // 操作日志通知
        @After("operationPointcut()")
        public void logOperation(JoinPoint joinPoint) {
            String username = SecurityContextHolder.getContext().getAuthentication().getName();
            String methodName = joinPoint.getSignature().getName();
            String operation = "execute " + methodName;
            OperationLog operationLog = new OperationLog();
            operationLog.setUsername(username);
            operationLog.setOperation(operation);
            operationLog.setOperationTime(new Date());
            logDao.saveOperationLog(operationLog);
        }
        
        注解:
        在这段代码中,使用了 @After 注解定义了一个通知方法 logOperation,该方法会在切点 operationPointcut() 匹配的目标方法执行后执行。下面是这段代码的详细解释:
    
    @After("operationPointcut()"):这里使用 @After 注解表示定义的是一个后置通知,当切点 operationPointcut() 匹配的方法执行完成后,logOperation 方法将会被调用。
    
    public void logOperation(JoinPoint joinPoint):logOperation 方法接收一个 JoinPoint 对象作为参数,该对象提供了关于连接点(即目标方法)的信息,如方法签名、参数等。
    
    String username = SecurityContextHolder.getContext().getAuthentication().getName();:通过 SecurityContextHolder 获取当前登录用户的认证信息,并获取用户名赋值给 username 变量。
    
    String methodName = joinPoint.getSignature().getName();:使用 joinPoint 对象的 getSignature().getName() 方法获取目标方法的名称,赋值给 methodName 变量。
    
    String operation = "execute " + methodName;:构造一个操作描述字符串,包含执行的方法名,赋值给 operation 变量。
    
    OperationLog operationLog = new OperationLog();:创建一个 OperationLog 对象,用于存储操作日志信息。
    
    operationLog.setUsername(username);:将用户名设置到 OperationLog 对象中。
    
    operationLog.setOperation(operation);:将操作描述设置到 OperationLog 对象中。
    
    operationLog.setOperationTime(new Date());:设置操作时间为当前时间。
    
    logDao.saveOperationLog(operationLog);:调用 logDao 对象的 saveOperationLog 方法保存操作日志信息到数据库。
    }
    
  4. 配置AOP

在Spring配置文件中配置AOP,指定切面和通知的织入方式。

<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.example.aspect"/>
  1. 在以上代码中,使用了Spring AOP的相关注解和配置来实现AOP的功能:

    • @Aspect:声明该类是一个切面类。
    • @Component:将该切面类作为一个Spring的Bean进行管理。
    • @Pointcut:定义切点,指定需要拦截的方法。
    • @AfterReturning:定义一个后置通知,表示在目标方法返回结果后执行。
    • @AfterThrowing:异常通知,在目标方法抛出异常时执行。
    • @After:定义一个后置通知,表示在目标方法执行后执行。
    • @Before:前置通知,在目标方法执行前执行。
    • @Around:环绕通知,在目标方法执行前后都可以执行自定义的行为。
    • JoinPoint:提供了对目标方法和目标对象的访问。
    • LogDao:日志持久化接口,定义了保存登录日志和操作日志的方法。
    • LogDaoImpl:日志持久化接口的实现类,负责将日志数据存储到数据库中。
    • LogAspect:AOP切面类,包含了登录日志和操作日志的相关通知方法。
    • @DeclareParents:引入增强,允许向现有的类添加新的方法和属性。
    • 配置文件中的<aop:aspectj-autoproxy/>用于启用自动代理功能,<context:component-scan>用于扫描并加载AOP切面类。
  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值