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

如何在Spring Data MongoDB中拦截MongoRepository并追加查询条件?

Spring Data MongoDB 统一追加查询Criteria的实现方案

下面提供几种可行的实现方式,按需选择:

方式一:自定义Repository基类重写查询逻辑

通过继承SimpleMongoRepository自定义Repository基类,在查询执行前统一追加Criteria条件。

  1. 编写自定义基类:
public class CustomMongoRepositoryImpl<T, ID> extends SimpleMongoRepository<T, ID> {

    private final MongoEntityInformation<T, ID> entityInformation;
    private final MongoOperations mongoOperations;

    public CustomMongoRepositoryImpl(MongoEntityInformation<T, ID> entityInformation, MongoOperations mongoOperations) {
        super(entityInformation, mongoOperations);
        this.entityInformation = entityInformation;
        this.mongoOperations = mongoOperations;
    }

    // 重写Example查询方法,追加统一条件
    @Override
    public List<T> findAll(Example<T> example) {
        Query query = Query.byExample(example);
        appendUnifiedCriteria(query);
        return mongoOperations.find(query, entityInformation.getJavaType());
    }

    // 重写派生查询的核心方法,覆盖所有自动生成的查询
    @Override
    protected Query createQuery(Example<T> example) {
        Query query = super.createQuery(example);
        appendUnifiedCriteria(query);
        return query;
    }

    // 统一追加条件的逻辑(示例:从上下文获取国家信息)
    private void appendUnifiedCriteria(Query query) {
        String currentCountry = getCurrentCountryFromContext();
        if (currentCountry != null) {
            query.addCriteria(Criteria.where("country").is(currentCountry));
        }
    }

    // 从上下文获取业务参数的示例方法
    private String getCurrentCountryFromContext() {
        return RequestContextHolder.getRequestAttributes() != null ?
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("X-Country") :
                null;
    }
}
  1. 配置Repository使用自定义基类:
    在Spring配置类中指定自定义基类:
@Configuration
@EnableMongoRepositories(
        basePackages = "com.yourpackage.repository",
        repositoryBaseClass = CustomMongoRepositoryImpl.class
)
public class MongoConfig {
}

方式二:实现QueryPostProcessor拦截查询

Spring Data MongoDB提供QueryPostProcessor接口,可在查询执行前直接修改Query对象,无需重写Repository基类。

  1. 实现QueryPostProcessor:
@Component
public class NameRepositoryQueryPostProcessor implements QueryPostProcessor<MongoQuery, Query> {

    @Override
    public Query postProcess(MongoQuery mongoQuery, Query query) {
        // 仅拦截NameRepository的查询
        if (NameRepository.class.isAssignableFrom(mongoQuery.getRepositoryInterface())) {
            String currentCountry = getCurrentCountryFromContext();
            if (currentCountry != null) {
                query.addCriteria(Criteria.where("country").is(currentCountry));
            }
        }
        return query;
    }

    private String getCurrentCountryFromContext() {
        return RequestContextHolder.getRequestAttributes() != null ?
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("X-Country") :
                null;
    }
}

该方式会自动被Spring Data MongoDB识别,拦截所有Mongo查询,可通过mongoQuery.getRepositoryInterface()精准控制拦截范围。

方式三:AOP切面拦截Repository查询方法

通过AOP直接拦截NameRepository的查询方法,手动修改或重建查询条件。

  1. 编写AOP切面:
@Aspect
@Component
public class NameRepositoryQueryAspect {

    @Autowired
    private MongoTemplate mongoTemplate;

    // 拦截NameRepository中所有以find开头的查询方法
    @Around("execution(* com.yourpackage.repository.NameRepository.find*(..))")
    public Object interceptQuery(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Object[] args = joinPoint.getArgs();

        // 构建Spring Data自动生成的查询对象
        MongoEntityInformation<Name, String> entityInfo = MongoEntityInformationSupport.getEntityInformation(Name.class, mongoTemplate);
        QueryLookupStrategy lookupStrategy = new MongoQueryLookupStrategy(mongoTemplate, mongoTemplate.getConverter(), null);
        RepositoryQuery repositoryQuery = lookupStrategy.resolveQuery(method, NameRepository.class, mongoTemplate.getConverter());
        
        if (repositoryQuery instanceof AbstractMongoQuery) {
            Query query = ((AbstractMongoQuery) repositoryQuery).createQuery(args);
            // 追加统一条件
            String currentCountry = getCurrentCountryFromContext();
            if (currentCountry != null) {
                query.addCriteria(Criteria.where("country").is(currentCountry));
            }
            
            // 根据方法返回类型执行查询
            Class<?> returnType = method.getReturnType();
            if (List.class.isAssignableFrom(returnType)) {
                return mongoTemplate.find(query, Name.class);
            } else if (Name.class.isAssignableFrom(returnType)) {
                return mongoTemplate.findOne(query, Name.class);
            }
        }
        
        // 无法处理时执行原方法
        return joinPoint.proceed();
    }

    private String getCurrentCountryFromContext() {
        return RequestContextHolder.getRequestAttributes() != null ?
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("X-Country") :
                null;
    }
}

注意事项

  • getCurrentCountryFromContext()仅为示例,实际可根据业务需求从ThreadLocal、用户会话、配置中心等渠道获取条件参数。
  • 若需要按需追加条件,可在逻辑中增加判断(如某些特定查询不需要追加时跳过)。
  • 方式二的QueryPostProcessor要求Spring Data MongoDB版本在2.2及以上。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:12:39