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

Java中避免REST API搜索方法复杂if-else分支的最优方案

优化多条件REST API搜索的复杂分支问题

嘿,这个场景我太熟了——多条件搜索里一堆null判断和嵌套if-else,时间长了代码简直像“意大利面”,维护起来头疼得很。下面给你几个实用的优化方案,从简单到进阶,你可以根据项目场景选:

方案1:建造者模式+JPA Specification(最推荐)

这个方案既能优雅封装查询参数,又能动态拼接查询条件,彻底告别冗余的if分支。

首先定义一个查询参数的封装类,用建造者模式来构建:

public class PersonSearchCriteria {
    private String name;
    private String city;
    private String state;
    private String code;

    // 私有构造,只能通过Builder创建
    private PersonSearchCriteria(Builder builder) {
        this.name = builder.name;
        this.city = builder.city;
        this.state = builder.state;
        this.code = builder.code;
    }

    // 生成所有字段的getter方法
    public String getName() { return name; }
    public String getCity() { return city; }
    public String getState() { return state; }
    public String getCode() { return code; }

    // 建造者内部类
    public static class Builder {
        private String name;
        private String city;
        private String state;
        private String code;

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder city(String city) {
            this.city = city;
            return this;
        }

        public Builder state(String state) {
            this.state = state;
            return this;
        }

        public Builder code(String code) {
            this.code = code;
            return this;
        }

        public PersonSearchCriteria build() {
            return new PersonSearchCriteria(this);
        }
    }
}

然后用JPA的Specification动态构建查询条件,自动过滤空值:

public List<Person> searchPerson(PersonSearchCriteria criteria) {
    Specification<Person> spec = (root, query, cb) -> {
        List<Predicate> predicates = new ArrayList<>();
        
        // 只给非空参数添加查询条件
        if (criteria.getName() != null) {
            predicates.add(cb.equal(root.get("name"), criteria.getName()));
        }
        if (criteria.getCity() != null) {
            predicates.add(cb.equal(root.get("city"), criteria.getCity()));
        }
        if (criteria.getState() != null) {
            predicates.add(cb.equal(root.get("state"), criteria.getState()));
        }
        if (criteria.getCode() != null) {
            predicates.add(cb.equal(root.get("code"), criteria.getCode()));
        }
        
        // 把所有条件用AND拼接
        return cb.and(predicates.toArray(new Predicate[0]));
    };
    
    return personRepository.findAll(spec);
}

调用的时候也很优雅:

// 比如只传name和city
PersonSearchCriteria criteria = new PersonSearchCriteria.Builder()
    .name("张三")
    .city("北京")
    .build();
List<Person> result = searchPerson(criteria);

优势:参数结构清晰,查询条件动态生成,扩展性极强——以后加新的查询参数,只需要在PersonSearchCriteria和Builder里加字段,再添一行predicate即可,完全不用改原有逻辑。

方案2:用Map统一封装参数(灵活轻量)

如果你的查询参数经常变动,或者不想写额外的实体类,可以用Map来接收参数,然后遍历处理非空值:

public List<Person> searchPerson(Map<String, String> params) {
    Specification<Person> spec = (root, query, cb) -> {
        List<Predicate> predicates = new ArrayList<>();
        
        // 遍历参数,只处理非空值
        params.forEach((key, value) -> {
            if (value != null && !value.trim().isEmpty()) {
                predicates.add(cb.equal(root.get(key), value));
            }
        });
        
        return cb.and(predicates.toArray(new Predicate[0]));
    };
    
    return personRepository.findAll(spec);
}

注意:这里的Map的key要和Person实体类的字段名严格对应,不然会抛出字段不存在的异常。如果需要做模糊查询,只需要把cb.equal换成cb.like就行,非常灵活。

方案3:Spring Data查询推导+Optional(简单场景适用)

如果你的查询组合比较固定,不想写复杂的Specification,可以用Spring Data的查询推导功能,结合Optional自动处理空值:

首先在Repository接口里定义方法:

public interface PersonRepository extends JpaRepository<Person, Long> {
    List<Person> findByNameAndCityAndStateAndCode(
        Optional<String> name, 
        Optional<String> city, 
        Optional<String> state, 
        Optional<String> code
    );
}

然后业务层调用:

public List<Person> searchPerson(String name, String city, String state, String code) {
    return personRepository.findByNameAndCityAndStateAndCode(
        Optional.ofNullable(name),
        Optional.ofNullable(city),
        Optional.ofNullable(state),
        Optional.ofNullable(code)
    );
}

优势:代码极简,不用自己写查询逻辑,Spring Data会自动生成对应的SQL。但缺点也很明显——如果需要支持多种参数组合(比如只查name+state,或者city+code),就需要在Repository里定义大量方法,扩展性差,适合简单的固定组合场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:01:59