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

如何通过Spring Data JPA Specification按指定companyId过滤作物数据?

Fixing CompanyId Filter in Spring Data JPA Specification Query

It looks like your current implementation isn't adding the companyId as a mandatory filter condition to your final query predicate, which is why you're getting results from all companies instead of just the specified one. Let's fix this with a few targeted changes:

Step 1: Update CropMasterSpecification to Enforce CompanyId

Your CropMasterSpecification already accepts a companyId in its constructor, but it isn't using it to build a filter. Let's modify the toPredicate method to always include the companyId match, and combine it with user-provided search criteria:

public class CropMasterSpecification implements Specification<CropMaster> {
    private SearchCriteria criteria;
    private Integer companyId;

    public CropMasterSpecification(final SearchCriteria criteria, final Integer companyId) {
        super();
        this.criteria = criteria;
        this.companyId = companyId;
    }

    public SearchCriteria getCriteria() {
        return criteria;
    }

    @Override
    public Predicate toPredicate(Root<CropMaster> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        // First, create the mandatory companyId filter
        Predicate companyFilter = criteriaBuilder.equal(root.get("companyId"), companyId);
        
        // Handle user search criteria if present
        Predicate searchFilter = null;
        if (criteria != null) {
            if (criteria.getOperation().equalsIgnoreCase(">")) {
                searchFilter = criteriaBuilder.greaterThanOrEqualTo(
                        root.<String>get(criteria.getKey()), criteria.getValue().toString());
            } else if (criteria.getOperation().equalsIgnoreCase("<")) {
                searchFilter = criteriaBuilder.lessThanOrEqualTo(
                        root.<String>get(criteria.getKey()), criteria.getValue().toString());
            } else if (criteria.getOperation().equalsIgnoreCase(":")) {
                if (root.get(criteria.getKey()).getJavaType() == String.class) {
                    searchFilter = criteriaBuilder.like(
                            root.<String>get(criteria.getKey()), "%" + criteria.getValue() + "%");
                } else {
                    searchFilter = criteriaBuilder.equal(root.get(criteria.getKey()), criteria.getValue());
                }
            }
        }
        
        // Combine the filters: companyId must match, plus any user search criteria
        return searchFilter != null 
            ? criteriaBuilder.and(companyFilter, searchFilter) 
            : companyFilter;
    }
}

Note: I removed the unnecessary companyId operation branch from your original code — since companyId is a fixed filter from the endpoint parameter, users shouldn't pass it via the search query string.

Step 2: Modify CropMasterSpecificationsBuilder to Pass CompanyId

Update the builder's build method to accept the companyId parameter, so it can pass this value to each CropMasterSpecification it creates:

public class CropMasterSpecificationsBuilder {
    private final List<SearchCriteria> params;

    public CropMasterSpecificationsBuilder() {
        params = new ArrayList<>();
    }

    public CropMasterSpecificationsBuilder with(String key, String operation, Object value) {
        params.add(new SearchCriteria(key, operation, value));
        return this;
    }

    // Updated build method to accept companyId
    public Specification<CropMaster> build(Integer companyId) {
        // If no search params, return only the companyId filter
        if (params.isEmpty()) {
            return (root, query, cb) -> cb.equal(root.get("companyId"), companyId);
        }

        List<Specification<CropMaster>> specs = new ArrayList<>();
        for (SearchCriteria param : params) {
            // Pass companyId to each specification
            specs.add(new CropMasterSpecification(param, companyId));
        }

        // Combine all search specifications with AND logic
        Specification<CropMaster> combinedSpec = specs.get(0);
        for (int i = 1; i < specs.size(); i++) {
            combinedSpec = Specifications.where(combinedSpec).and(specs.get(i));
        }

        return combinedSpec;
    }

    public final CropMasterSpecificationsBuilder with(SearchCriteria criteria) {
        params.add(criteria);
        return this;
    }
}

Step 3: Update Your REST Service to Use the Updated Builder

In your getCropMasters method, pass the companyId parameter to the builder's build method, and mark companyId as required to avoid accidental null values:

public Page<CropMasterDTO> getCropMasters(
        @NotNull Integer companyId,
        Pageable pageable,
        LocalDateTime lastModifiedDateTime,
        Integer langaugeIdForUser,
        String search) {

    CropMasterSpecificationsBuilder builder = new CropMasterSpecificationsBuilder();
    
    // Parse search parameters if provided
    if (search != null && !search.isBlank()) {
        Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),");
        Matcher matcher = pattern.matcher(search + ",");
        while (matcher.find()) {
            builder.with(matcher.group(1), matcher.group(2), matcher.group(3));
        }
    }
    
    // Build specification with companyId filter
    Specification<CropMaster> spec = builder.build(companyId);
    Page<CropMaster> cropMasters = cropMasterRepository.findAll(spec, pageable);
    
    // Map to DTOs and return
    CropMasterDTOMapper mapper = Mappers.getMapper(CropMasterDTOMapper.class);
    List<CropMasterDTO> cropMasterDTOs = mapper.cropMasterToDTOs(cropMasters.getContent());
    return new PageImpl<>(cropMasterDTOs, pageable, cropMasters.getTotalElements());
}

Test the Fix

Now when you call your endpoint like this:

http://localhost:8080/cropMaster/list?companyId=YOUR_COMPANY_ID&search=cropName:Cucumber,scientificName:Cucumber

You'll only get results where companyId matches the value you passed, plus the search criteria from the search parameter.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:12:12