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

如何在分层架构的REST API中通过请求参数实现动态搜索?

问题:REST API添加搜索参数的实现方案

我现在的REST API采用Controller->Service->Repository分层架构,已经实现了获取所有司机的GET接口:

@GetMapping
public ResponseEntity<Set<DriverDTO>> getAll(@PageableDefault(value = 15) Pageable pageable) {

    Page<DriverEntity> driverEntities = driverService.getAll(pageable);
    Set<DriverDTO> driverDTOSet = modelMapperService.mapPageToSetOfEnteredClass(driverEntities, DriverDTO.class);
    return new ResponseEntity<>(driverDTOSet, HttpStatus.OK);
}

现在想添加name、ageUpTo、ageOver等搜索参数,已经在接口中添加了@RequestParams:

@GetMapping
public ResponseEntity<Set<DriverDTO>> getAll(@PageableDefault(value = 15) Pageable pageable,
                                             @RequestParam String name,
                                             @RequestParam int ageUpTo,
                                             @RequestParam int ageOver) {
    Page<DriverEntity> driverEntities = driverService.getAll(pageable);
    Set<DriverDTO> driverDTOSet = modelMapperService.mapPageToSetOfEnteredClass(driverEntities, DriverDTO.class);
    return new ResponseEntity<>(driverDTOSet, HttpStatus.OK);
}

Service层的getAll方法如下:

public Page<DriverEntity> getAll(Pageable pageable) {
    return driverEntityRepository.findAll(pageable);
}

接下来该如何实现?是否需要将每个请求参数都传入getAll方法,通过if判断参数是否为空,还是使用switch语句?


实现步骤

1. 调整Controller的请求参数配置

当前的@RequestParam都是必填规则,不符合搜索场景(用户通常只会传部分参数),需要改成可选配置,同时把基本类型换成包装类,避免默认值干扰判断:

@GetMapping
public ResponseEntity<Set<DriverDTO>> getAll(@PageableDefault(value = 15) Pageable pageable,
                                             @RequestParam(required = false) String name,
                                             @RequestParam(required = false) Integer ageUpTo,
                                             @RequestParam(required = false) Integer ageOver) {
    Page<DriverEntity> driverEntities = driverService.getAll(pageable, name, ageUpTo, ageOver);
    Set<DriverDTO> driverDTOSet = modelMapperService.mapPageToSetOfEnteredClass(driverEntities, DriverDTO.class);
    return new ResponseEntity<>(driverDTOSet, HttpStatus.OK);
}

如果后续参数增多,建议封装成查询DTO来优化代码整洁度:

// 定义查询参数DTO
public class DriverQueryDTO {
    private String name;
    private Integer ageUpTo;
    private Integer ageOver;
    // getter、setter方法
}

// Controller修改为
@GetMapping
public ResponseEntity<Set<DriverDTO>> getAll(@PageableDefault(value = 15) Pageable pageable,
                                             DriverQueryDTO queryDTO) {
    Page<DriverEntity> driverEntities = driverService.getAll(pageable, queryDTO);
    // 后续转换逻辑不变
}

2. 修改Service层,实现动态条件查询

不需要用switch,直接用if判断参数是否存在即可。推荐用JPA的Specification实现动态查询,比硬写SQL更灵活适配多条件场景:

// Service层方法修改(直接传参数版)
public Page<DriverEntity> getAll(Pageable pageable, String name, Integer ageUpTo, Integer ageOver) {
    Specification<DriverEntity> spec = (root, query, cb) -> {
        List<Predicate> predicates = new ArrayList<>();
        // 处理name模糊匹配
        if (StringUtils.isNotBlank(name)) {
            predicates.add(cb.like(root.get("name"), "%" + name + "%"));
        }
        // 处理ageUpTo:年龄≤指定值
        if (ageUpTo != null) {
            predicates.add(cb.lessThanOrEqualTo(root.get("age"), ageUpTo));
        }
        // 处理ageOver:年龄>指定值
        if (ageOver != null) {
            predicates.add(cb.greaterThan(root.get("age"), ageOver));
        }
        return cb.and(predicates.toArray(new Predicate[0]));
    };
    return driverEntityRepository.findAll(spec, pageable);
}

// 如果用DTO的话,方法签名和逻辑调整为
public Page<DriverEntity> getAll(Pageable pageable, DriverQueryDTO queryDTO) {
    Specification<DriverEntity> spec = (root, query, cb) -> {
        List<Predicate> predicates = new ArrayList<>();
        if (StringUtils.isNotBlank(queryDTO.getName())) {
            predicates.add(cb.like(root.get("name"), "%" + queryDTO.getName() + "%"));
        }
        if (queryDTO.getAgeUpTo() != null) {
            predicates.add(cb.lessThanOrEqualTo(root.get("age"), queryDTO.getAgeUpTo()));
        }
        if (queryDTO.getAgeOver() != null) {
            predicates.add(cb.greaterThan(root.get("age"), queryDTO.getAgeOver()));
        }
        return cb.and(predicates.toArray(new Predicate[0]));
    };
    return driverEntityRepository.findAll(spec, pageable);
}

3. 让Repository支持Specification

需要让你的DriverEntityRepository继承JpaSpecificationExecutor接口,才能使用Specification查询:

public interface DriverEntityRepository extends JpaRepository<DriverEntity, Long>, JpaSpecificationExecutor<DriverEntity> {
}

替代方案:自定义Repository查询方法

如果查询逻辑简单,也可以直接在Repository中定义带条件的查询方法:

// Repository中定义
Page<DriverEntity> findByNameContainingAndAgeLessThanOrEqualToAndAgeGreaterThan(String name, Integer ageUpTo, Integer ageOver, Pageable pageable);

但这种方式的局限性是:当参数为null时,会将null作为匹配条件,而非忽略该条件,所以更适合固定条件的查询,多可选条件场景还是Specification更实用。

总结

  • 不需要用switch,用if判断参数是否存在即可实现动态条件拼接
  • 推荐用JPA Specification适配多条件可选的搜索场景,灵活性更高
  • 参数较多时封装成DTO,提升代码可读性和维护性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:06:38