You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring-Mongo集成Javers:如何在onSaveAll前过滤审计数据?

Solutions to Filter Data Before Javers' onSaveAllExecuted() Audit

Got it, I’ve faced a similar requirement before when working with Javers and Spring Data MongoDB. Here are a few practical solutions you can try to filter data before Javers’ audit kicks in:

1. Custom Repository Implementation (Most Straightforward)

Instead of trying to intercept the Javers aspect directly, override the saveAll method in your repository to filter entities before they reach the Javers audit logic. This gives you full control over which entities get audited.

Example Code:

First, define a custom repository interface:

public interface CustomizedAuditableRepository<T> {
    <S extends T> List<S> saveAll(Iterable<S> entities);
}

Then implement it, adding your filtering logic:

public class CustomizedAuditableRepositoryImpl<T> implements CustomizedAuditableRepository<T> {
    private final MongoRepository<T, ?> baseRepository;
    private final MongoTemplate mongoTemplate;

    public CustomizedAuditableRepositoryImpl(MongoRepository<T, ?> baseRepository, MongoTemplate mongoTemplate) {
        this.baseRepository = baseRepository;
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public <S extends T> List<S> saveAll(Iterable<S> entities) {
        // Split entities into auditable and non-auditable groups
        Map<Boolean, List<S>> splitEntities = StreamSupport.stream(entities.spliterator(), false)
                .collect(Collectors.partitioningBy(this::shouldAudit));

        // Save auditable entities via the base repository (triggers Javers audit)
        List<S> auditedSaved = baseRepository.saveAll(splitEntities.get(true));

        // Save non-auditable entities directly with MongoTemplate (bypasses Javers)
        splitEntities.get(false).forEach(mongoTemplate::save);

        return Stream.concat(auditedSaved.stream(), splitEntities.get(false).stream())
                .collect(Collectors.toList());
    }

    private boolean shouldAudit(S entity) {
        // Add your custom filtering logic here
        // Example: Check if the entity doesn't have an "ignoreAudit" flag
        if (entity instanceof AuditableMarker) {
            return !((AuditableMarker) entity).isIgnoreAudit();
        }
        return true;
    }
}

Finally, extend your main repository interface with the custom one:

public interface UserRepository extends MongoRepository<User, String>, CustomizedAuditableRepository<User> {
}

Pros: Direct control over data flow, no dependency on Javers' internal aspects.
Cons: Requires implementing this for each repository that needs filtering.

2. High-Priority Custom Aspect (Global Filtering)

If you want a global solution without modifying every repository, create a custom Spring AOP aspect that runs before Javers' JaversSpringDataAuditableRepositoryAspect. You can modify the saveAll method arguments to filter entities before Javers processes them.

Example Code:

@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // Ensure this runs before Javers' aspect
public class JaversPreFilterAspect {

    @Around("execution(* org.springframework.data.mongodb.repository.MongoRepository.saveAll(..)) && @annotation(org.javers.spring.annotation.JaversSpringDataAuditable)")
    public Object filterEntitiesBeforeAudit(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        
        // Check if the first argument is an Iterable of entities
        if (args.length > 0 && args[0] instanceof Iterable) {
            Iterable<?> originalEntities = (Iterable<?>) args[0];
            // Filter entities based on your rules
            List<?> filteredEntities = StreamSupport.stream(originalEntities.spliterator(), false)
                    .filter(this::isEligibleForAudit)
                    .collect(Collectors.toList());
            // Replace the original argument with filtered list
            args[0] = filteredEntities;
        }
        
        // Proceed with the modified arguments (Javers will process the filtered list)
        return joinPoint.proceed(args);
    }

    private boolean isEligibleForAudit(Object entity) {
        // Custom logic: e.g., exclude entities of a specific type
        return !(entity instanceof TemporaryEntity);
    }
}

Pros: Applies filtering globally to all repositories annotated with @JaversSpringDataAuditable.
Cons: Relies on Spring AOP ordering, which could break if Javers changes its aspect's order in future versions.

3. Javers Custom Change Filter (Post-Change Generation)

If the above options don't work, you can intercept Javers' commit process to filter out unwanted changes after they're generated but before they're saved to the audit store. This is less efficient but useful if you need to filter based on change details (not just entity properties).

Example Code:

@Component
public class FilteringJaversCommitListener implements CommitListener {

    @Override
    public void onCommit(Commit commit, Javers javers) {
        // Filter out changes that don't need to be audited
        List<Change> filteredChanges = commit.getChanges().stream()
                .filter(change -> shouldKeepChange(change))
                .collect(Collectors.toList());
        
        // If no changes left, skip saving the commit
        if (filteredChanges.isEmpty()) {
            return;
        }
        
        // Create a new commit with filtered changes and save it manually
        Commit filteredCommit = new Commit(commit.getMetadata(), filteredChanges);
        javers.getRepository().commit(filteredCommit);
    }

    private boolean shouldKeepChange(Change change) {
        // Example: Exclude changes to the "lastLogin" field
        if (change instanceof PropertyChange) {
            PropertyChange propertyChange = (PropertyChange) change;
            return !"lastLogin".equals(propertyChange.getPropertyName());
        }
        return true;
    }
}

Pros: Can filter based on specific change details (e.g., which field was modified).
Cons: Generates unnecessary changes first, which is less performant.


内容的提问来源于stack exchange,提问作者Ketan Nabera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 21:07:39