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

Spring Boot中Rest API过滤:合并相似查询接口为带Filter参数接口

合并Spring Boot相似接口的实现方案

这事儿我刚在项目里实践过,其实很容易落地,咱们一步步拆解来做:

1. 先定义筛选类型的枚举(推荐)

首先把你需要的filter可选值做成枚举,既避免硬编码字符串,还能方便后续的参数校验和逻辑分发:

public enum PostFilter {
    POPULAR, LATEST, DEFAULT;

    // 可选:把传入的字符串转为枚举,忽略大小写,兼容用户输入
    public static PostFilter fromString(String filterStr) {
        if (filterStr == null || filterStr.isBlank()) {
            return DEFAULT;
        }
        try {
            return PostFilter.valueOf(filterStr.toUpperCase());
        } catch (IllegalArgumentException e) {
            return DEFAULT; // 也可以抛出参数非法异常,根据你的业务容错需求来定
        }
    }
}

2. 修改控制器接口

把原来的三个接口合并成一个,用@RequestParam接收filter参数,并且设置默认值,这样不传filter的时候就走默认的帖子搜索逻辑:

@RestController
@RequestMapping("/search")
public class PostController {

    @Autowired
    private PostService postService;

    @GetMapping("/{topicId}")
    public ResponseEntity<List<Post>> getPosts(
            @PathVariable Long topicId,
            @RequestParam(value = "filter", defaultValue = "default") String filterStr) {
        
        // 把前端传入的字符串转成枚举类型
        PostFilter filter = PostFilter.fromString(filterStr);
        
        // 根据筛选类型分发到对应的业务逻辑
        List<Post> posts;
        switch (filter) {
            case POPULAR:
                posts = postService.getPopularPosts(topicId);
                break;
            case LATEST:
                posts = postService.getLatestPosts(topicId);
                break;
            default:
                posts = postService.searchPosts(topicId);
                break;
        }
        
        return ResponseEntity.ok(posts);
    }
}

3. (可选)用策略模式优化逻辑分发

如果后续筛选类型越来越多,switch-case会变得臃肿难维护,这时候可以用策略模式来优化:

第一步:定义策略接口

public interface PostFilterStrategy {
    List<Post> getPosts(Long topicId);
    PostFilter getFilterType();
}

第二步:实现各个策略类

@Component
public class PopularPostStrategy implements PostFilterStrategy {
    @Autowired
    private PostService postService;

    @Override
    public List<Post> getPosts(Long topicId) {
        return postService.getPopularPosts(topicId);
    }

    @Override
    public PostFilter getFilterType() {
        return PostFilter.POPULAR;
    }
}

// 同理实现LatestPostStrategy和DefaultPostStrategy

第三步:在控制器中注入策略映射

@RestController
@RequestMapping("/search")
public class PostController {

    private final Map<PostFilter, PostFilterStrategy> strategyMap;

    // 构造函数注入,Spring会自动把所有PostFilterStrategy实现类注入到map中
    public PostController(List<PostFilterStrategy> strategies) {
        this.strategyMap = strategies.stream()
                .collect(Collectors.toMap(PostFilterStrategy::getFilterType, Function.identity()));
    }

    @GetMapping("/{topicId}")
    public ResponseEntity<List<Post>> getPosts(
            @PathVariable Long topicId,
            @RequestParam(value = "filter", defaultValue = "default") String filterStr) {
        
        PostFilter filter = PostFilter.fromString(filterStr);
        // 获取对应的策略,找不到就用默认策略兜底
        PostFilterStrategy strategy = strategyMap.getOrDefault(filter, strategyMap.get(PostFilter.DEFAULT));
        List<Post> posts = strategy.getPosts(topicId);
        
        return ResponseEntity.ok(posts);
    }
}

4. 参数校验(推荐)

为了避免用户传入非法的filter值,你可以加上参数校验逻辑:
比如自定义校验注解:

// 自定义校验注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PostFilterValidator.class)
public @interface ValidPostFilter {
    String message() default "Invalid filter value. Allowed values: popular, latest, default";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

// 校验器实现
public class PostFilterValidator implements ConstraintValidator<ValidPostFilter, String> {
    private static final Set<String> ALLOWED_VALUES = Set.of("popular", "latest", "default");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null || value.isBlank()) {
            return true; // 允许空值,因为我们有默认值兜底
        }
        return ALLOWED_VALUES.contains(value.toLowerCase());
    }
}

然后在控制器参数上加上@ValidPostFilter:

@GetMapping("/{topicId}")
public ResponseEntity<List<Post>> getPosts(
        @PathVariable Long topicId,
        @RequestParam(value = "filter", defaultValue = "default") @ValidPostFilter String filterStr) {
    // 后续逻辑不变
}

这样一来,用户访问以下URL都会走同一个接口,并且根据filter参数分发到对应的逻辑:

  • GET /search/123 → 默认帖子搜索
  • GET /search/123?filter=popular → 热门帖子查询
  • GET /search/123?filter=latest → 最新帖子查询

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:53:29