Spring AOP:在数据库中实现活动日志的最佳方法

问题描述 投票:3回答:4

我一直在看一些Spring AOP的教程,对相关的概念已经有了一定的了解。

现在来到我的需求,我需要创建一个活动日志的实现,它将保存一个登录用户在DB中的活动,这些活动的范围可以从申请服务或创建新用户的情况。Admin 用户等。在调用任何有注解的方法时(比如说 @ActivityLog),这些信息将以以下形式存在。actorId, actionComment, actionTime, actedUponId,......等等。

现在,如果我创建一个POJO类(它映射到一个 ActivityLog 表),并希望将这些数据从数据库中的 Advice (最好使用与方法相同的交易,方法使用的是 @Transactional 注解),我如何实际填充这个POJO中的变量?我大概可以在这个POJO中得到 actorId 的会话对象&amp。actionTime 可以简单地将 new Date() 的动态值呢?actionComment actedUponId?

任何帮助将是辉煌的! 顺便说一下,我有一个要求,就是不能使用Hibernate拦截器)。

spring aop aspectj
4个回答
2
投票

这里是一个完整的例子。

@Aspect
@Component
public class WebMethodAuditor {

protected final Log logger = LogFactory.getLog(getClass());

public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";

@Autowired
AuditRecordDAO auditRecordDAO; 

@Before("execution(* com.mycontrollers.*.*(..))")
public void beforeWebMethodExecution(JoinPoint joinPoint) {
    Object[] args = joinPoint.getArgs();
    String methodName = joinPoint.getSignature().getName();
    User principal = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    Timestamp timestamp = new Timestamp(new java.util.Date().getTime());
    // only log those methods called by an end user
    if(principal.getUsername() != null) {
        for(Object o : args) {
            Boolean doInspect = true;
            if(o instanceof ServletRequestDataBinder) doInspect = false;
            if(o instanceof ExtendedModelMap) doInspect = false;
            if(doInspect) {
                if(o instanceof BaseForm ) {
                    // only show form objects
                    AuditRecord ar = new AuditRecord();
                    ar.setUsername(principal.getUsername());
                    ar.setClazz(o.getClass().getCanonicalName());
                    ar.setMethod(methodName);
                    ar.setAsString(o.toString());
                    ar.setAudit_timestamp(timestamp);
                    auditRecordDAO.save(ar);
                }
            }
        }
    }
}

}

2
投票

如果你正在寻找得到 actionCommentactedUponId 从参数到注解方法(假设它们都是字符串),你可以将绑定项添加到你的 @Around 点切这样。

@Around("@annotation(ActivityLog) && args(actionComment,actedUponId)")
public Object logActivity(ProceedingJoinPoint pjp,
        String actionComment, String actedUponId) throws Throwable {
    // ... get other values from context, etc. ...
    // ... write to log ...
    pjp.proceed();
}

The args 点切中的绑定可以在部分指定模式下使用,以防有其他关于你不感兴趣的参数,由于方面本身就是一个bean,所以它可以以正常的方式被连接到其他一切正在进行的事情中。

需要注意的是,如果你在同一个方法调用上混合了声明式事务管理,你就必须把方面的顺序搞对。这在一定程度上是通过让方面Bean也实现Spring的 Ordered 接口,并通过控制交易的优先级,通过 order 归于 <tx:annotation-driven/>. (如果这是不可能的,你将被迫用直接交易处理来做聪明的事情;那是一个更痛苦的选择,要搞好...)


0
投票

你将得到一个参考 org.aspectj.lang.JoinPoint 在你的建议中,你可以通过以下方法获得正在执行的目标方法的名称 toShortString().你可以有一个循环属性文件,其中包含了 method-name=comments 这些注释可以被填入到 "我的名字 "中。POJO.actionComment.method-name可以设置为 POJO.actedUponId.

我希望建议应该在同一个事务内运行,如果数据访问方法被建议,服务方法使用@Transactional。

© www.soinside.com 2019 - 2024. All rights reserved.