我一直在阅读一些Spring / AOP教程,并对相关概念有所了解。
现在满足我的要求,我需要创建一个活动日志实现,它将保存登录用户在数据库中的活动,其中包括申请服务或创建新用户{{1}在调用具有注释的任何方法(例如Admin
)时,此信息将以@ActivityLog
,actorId
,actionComment
的形式保留, actionTime
,......等。
现在,如果我创建一个POJO类(映射到数据库中的actedUponId
表)并希望从ActivityLog
内部保存这些数据(最好使用与方法相同的事务,方法使用Advice
注释),我如何实际填充此POJO中的变量?我可以从会话对象&中获得@Transactional
。 actorId
可以只是actionTime
,但new Date()
/ actionComment
的动态值怎么样?
任何帮助都将是辉煌的! (顺便说一句,我要求不使用Hibernate拦截器。)
答案 0 :(得分: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);
}
}
}
}
}
}
答案 1 :(得分:2)
如果您希望从带注释方法的参数中获取actionComment
和actedUponId
(假设它们都是字符串),您可以将绑定项添加到@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();
}
切入点中的args
绑定可以在部分指定的模式下使用,如果有其他关于你不感兴趣的参数,并且因为方面本身就是一个bean,它可以被连线以正常方式进行的其他事情。
请注意,如果您在相同的方法调用上混合声明式事务管理,则必须使方面的顺序正确。这部分是通过使aspect bean实现Spring Ordered
接口,并通过order
属性控制事务的优先级到<tx:annotation-driven/>
来完成的。 (如果这是不可能的,你将被迫通过直接交易处理做出聪明的事情;这是一个更加痛苦的选择,以便做对......)
答案 2 :(得分:0)
您将在您的建议中获得对org.aspectj.lang.JoinPoint
的引用。您可以使用toShortString()
获取正在执行的目标方法的名称。您可以拥有带{的循环/属性文件{1}}条目。此评论可以填充到method-name=comments
。方法名称可以设置为POJO.actionComment
。
我希望建议应该在同一个事务中运行,如果建议使用数据访问方法并且服务方法使用@Transactional。