下一篇文章将演示如何使用Spring AOP和注释编写简单的审计。 审核机制将是干净,高效且易于维护的(和Kewwl!)。
我将在用户管理系统上演示我的示例(假设您对反射和AOP具有一般知识)。
我们从简单的数据库表开始,以保存我们的审计数据:
`id`,`username``user_type``action``target_user``date``user_ip`
我们需要填充4个主要字段(用户名,用户类型,操作,目标用户)
*用户名–执行操作的用户
* TargetUser –执行操作的目标用户。
现在,让我们创建新的注释以标记我们的“想被审计”方法。 我们将非常“有创意”并使用:@AuditAble
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Auditable {
AuditingActionType actionType();
}
带注释的@AuditAble方法示例:
@Override@Transactional@Auditable(actionType = AuditingActionType.INTERNAL_USER_REGISTRATION)public void createInternalUser(UserDTO userDTO) {userCreationService.createInternalUserOnDB(userDTO);}
我们未来的Aspect(aop)将使用DTO从方法参数中收集一些审核数据。 在我们的情况下,将收集目标用户名和actionType作为我们的审核信息。
为此,我创建了另一个注释AuditingTargetUsername :
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface AuditingTargetUsername {
String value() default "";
}
因此,在UserDTO内部,我们得到了:
public abstract class UserDTO implements Serializable {@NotNull@AuditingTargetUsernameprivate String userName;...}
我们用@AuditingTargetUsername注释了userName。 该信息将在以后收集。
现在,让我们创建AOP的方面。 此处收集并执行所有审核逻辑(拦截@Auditable方法,从批注中提取信息,使用存储库保存最终审核记录):
@Aspect
public class AuditingAspect {....@After("@annotation(auditable)")@Transactionalpublic void logAuditActivity(JoinPoint jp, Auditable auditable) {String targetAuditingUser;String actionType = auditable.actionType().getDescription();String auditingUsername = Authentication auth = SecurityContextHolder.getContext().getAuthentication().getName()role = userService.getCurrentUser(false).getPermissionsList().toString();auditingUsernameIp = request.getRemoteAddr();}logger.info("Auditing information. auditingUsername=" + auditingUsername + ", actionType=" + actionType + ", role=" + role + ", targetAuditingUser="+ targetAuditingUser + " auditingUsernameIp=" + auditingUsernameIp);auditingRepository.save(new AuditingEntity(auditingUsername, role, actionType, targetAuditingUser, auditingUsernameIp,new Timestamp(new java.util.Date().getTime())));}
ill解释了主要的代码区域:
切入点–所有@ Auditable.annotations
建议–键入@After(我们希望在调用该方法之后进行审核)
通过带注释的方法的声明检索ActionType值:
@Auditable( actionType = AuditingActionType.INTERNAL_USER_REGISTRATION )
auditingUsername是执行操作的当前用户(在本例中为登录用户)。 我是通过SecurityContext(Spring Security)检索到的。
现在,我们将通过运行时的反射来提取@targetAuditingUser字段:
targetAuditingUser = extractTargetAuditingUser(jp.getArgs());
...public String extractTargetAuditingUserFromAnnotation(Object obj) {
...result = getTargetAuditingUserViaAnnotation(obj);...}
这就是通过反射提取带注释的字段的逻辑:
private String getTargetAuditingUserViaAnnotation(Object obj) {
class cl=obj.getClass()String result = null;try {for (Field f : cl.getDeclaredFields())for (Annotation a : f.getAnnotations()) {if (a.annotationType() == AuditingTargetUsername.class) {f.setAccessible(true);Field annotatedFieldName = cl.getDeclaredField(f.getName());annotatedFieldName.setAccessible(true);String annotatedFieldVal = (String) annotatedFieldName.get(obj);logger.debug("Found auditing annotation. type=" + a.annotationType() + " value=" + annotatedFieldVal.toString());result = annotatedFieldVal;}}} catch (Exception e) {logger.error("Error extracting auditing annotations from obj" + obj.getClass());}return result;}
DB上的结果:
而已。 我们拥有干净的审核基础结构,您所需要做的就是用@Auditable注释您的方法,并在DTO /实体内部注释所需的待审核信息。
伊丹
翻译自: https://www.javacodegeeks.com/2014/07/auditing-infrastructure-for-your-app-using-spring-aop-custom-annotations-and-reflection.html