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

基于Spring Data Rest的Spring Boot动态查询实现困境

解决Spring Boot 1.5.9 + Spring Data Rest动态SQL过滤的依赖注入问题

你遇到的核心问题其实是Spring Data Rest的Repository代理机制和Request Scope Bean注入的冲突——Spring Data会为你的Repository接口生成动态代理对象,你自定义的抽象实现类和默认方法没法直接拿到Spring容器里的Request Scope Bean。下面是一步步的解决方案:

问题根源拆解

  • Spring Data Rest生成的Repository代理不会继承你写的SampleRepositoryComponents的Autowired属性,因为代理是基于接口动态生成的,和你的抽象Component类没有关联;
  • Repository接口的默认方法不属于Spring的Bean方法生命周期范畴,没法直接注入或访问Spring容器中的Bean。

解决方案步骤

1. 正确配置Request Scope的QueryParam Bean

首先确保QueryParam被正确注册为Request Scope的Bean,并且启用代理模式,这样在单例Bean中注入它时能正常工作:

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class QueryParam {
    private String query_string;
    private Map<String, String[]> parameter_map;

    // Getters & Setters
    public String getQuery_string() { return query_string; }
    public void setQuery_string(String query_string) { this.query_string = query_string; }
    public Map<String, String[]> getParameter_map() { return parameter_map; }
    public void setParameter_map(Map<String, String[]> parameter_map) { this.parameter_map = parameter_map; }
}

2. 实现拦截器,把请求参数存入QueryParam

修改你的拦截器,直接注入QueryParam并设置请求参数:

@Component
public class QueryParamInterceptor extends HandlerInterceptorAdapter {

    private final QueryParam queryParam;

    @Autowired
    public QueryParamInterceptor(QueryParam queryParam) {
        this.queryParam = queryParam;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        queryParam.setQuery_string(request.getQueryString());
        queryParam.setParameter_map(request.getParameterMap());
        return true;
    }
}

别忘了在Web配置中注册拦截器:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    private final QueryParamInterceptor queryParamInterceptor;

    @Autowired
    public WebConfig(QueryParamInterceptor queryParamInterceptor) {
        this.queryParamInterceptor = queryParamInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(queryParamInterceptor)
                .addPathPatterns("/Sample/**"); // 只针对你的Sample接口路径,更高效
    }
}

3. 让Specification能获取QueryParam

因为Specification本身不是Spring管理的Bean,我们让它实现ApplicationContextAware来获取Spring上下文,从而拿到Request Scope的QueryParam:

public class QuerySpecification<T> implements Specification<T>, ApplicationContextAware {
    private static ApplicationContext applicationContext;
    private QueryParam queryParam;

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        applicationContext = ctx;
    }

    public QuerySpecification() {
        // 通过上下文获取Request Scope的QueryParam,代理模式会自动绑定当前请求的实例
        this.queryParam = applicationContext.getBean(QueryParam.class);
    }

    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        // 这里可以正常使用queryParam里的参数构建过滤逻辑
        Map<String, String[]> params = queryParam.getParameter_map();
        String queryString = queryParam.getQuery_string();

        // 示例:根据name参数构建模糊查询
        Predicate predicate = criteriaBuilder.conjunction();
        if (params != null && params.containsKey("name")) {
            predicate = criteriaBuilder.and(predicate,
                    criteriaBuilder.like(root.get("name"), "%" + params.get("name")[0] + "%"));
        }
        return predicate;
    }
}

4. 简化Repository接口

现在Repository接口不需要再处理QueryParam的注入了,直接在默认的findAll方法中使用QuerySpecification:

@RepositoryRestResource(collectionResourceRel = "Sample", path = "Sample")
public interface SampleRepository extends PagingAndSortingRepository<Sample, UUID>, JpaSpecificationExecutor<Sample> {

    @Override
    default Page<Sample> findAll(Pageable pageable) {
        return findAll(new QuerySpecification<>(), pageable);
    }
}

为什么之前的方案行不通?

  • 你写的SampleRepositoryComponents抽象类虽然实现了Repository接口,但Spring Data Rest生成的动态代理不会关联这个类的Autowired属性,导致getQuery_param()始终返回null;
  • Repository接口的默认方法不受Spring的Bean生命周期管理,没法直接访问Spring容器中的Bean,所以依赖注入不会生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:40:35