如何在REST调用中分离映射动态查询参数与Pageable信息?
问题描述
处理REST接口时,前端会在URL中传入page、size、sort等分页参数,以及数量不固定的动态查询参数。当前参数映射方式如下:
请求示例
http://localhost:8080/something/search?page=0&size=10&sort=applicationId,asc&applicationId=name1&applicationId=name2&reference=12345
参数映射代码
public ResponseEntity<Page<ObjectToReturn>> getObjectWithDynamicCriteria(Pageable pageable, @RequestParam MultiValueMap<String, String> params)
当前问题
Pageable对象与MultiValueMap中同时包含分页相关信息:
Page request [number: 0, size 10, sort: applicationId: ASC] params {page=[0], size=[10], sort=[applicationId,asc], applicationId=[name1, name2], reference=[12345]}
需要处理MultiValueMap中的applicationId、reference等动态参数,但必须先移除其中的page、size、sort信息,希望让MultiValueMap仅保留动态查询参数。
解决方案
方法1:手动移除分页参数
这是最简单直接的方式,在方法内部直接删除MultiValueMap中的分页相关key:
public ResponseEntity<Page<ObjectToReturn>> getObjectWithDynamicCriteria(Pageable pageable, @RequestParam MultiValueMap<String, String> params) { // 移除分页参数 params.remove("page"); params.remove("size"); params.remove("sort"); // 处理剩余的动态查询参数 // ... return ResponseEntity.ok(...); }
如果不想修改原始参数Map,可以先复制一份再操作:
// 复制原始参数到新的Map MultiValueMap<String, String> dynamicParams = new LinkedMultiValueMap<>(params); // 移除分页参数 dynamicParams.remove("page"); dynamicParams.remove("size"); dynamicParams.remove("sort");
方法2:自定义参数解析器(适合多接口复用)
如果多个接口都需要过滤分页参数,可以自定义参数解析器,自动处理参数过滤:
- 定义自定义注解,标记需要过滤的参数:
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface DynamicQueryParams { }
- 实现参数解析器:
public class DynamicQueryParamsResolver implements HandlerMethodArgumentResolver { // 定义需要过滤的分页参数集合 private static final Set<String> PAGE_PARAMS = Set.of("page", "size", "sort"); @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterAnnotation(DynamicQueryParams.class) != null && MultiValueMap.class.isAssignableFrom(parameter.getParameterType()); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { MultiValueMap<String, String> dynamicParams = new LinkedMultiValueMap<>(); // 遍历所有请求参数,过滤掉分页参数 webRequest.getParameterMap().forEach((key, values) -> { if (!PAGE_PARAMS.contains(key)) { dynamicParams.put(key, Arrays.asList(values)); } }); return dynamicParams; } }
- 注册解析器到Spring配置:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new DynamicQueryParamsResolver()); } }
- 在接口中使用自定义注解:
public ResponseEntity<Page<ObjectToReturn>> getObjectWithDynamicCriteria(Pageable pageable, @DynamicQueryParams MultiValueMap<String, String> dynamicParams) { // dynamicParams中仅包含动态查询参数,无需手动处理分页参数 // ... return ResponseEntity.ok(...); }
方法3:利用Spring Data Querydsl自动处理动态查询(可选)
如果项目中使用Querydsl,可以借助Spring Data的特性,让框架自动转换动态参数为查询条件,同时分页参数由Pageable单独处理:
- 扩展Repository接口:
public interface ObjectToReturnRepository extends JpaRepository<ObjectToReturn, Long>, QuerydslPredicateExecutor<ObjectToReturn> { }
- 在接口方法中使用
@QuerydslPredicate:
@Autowired private ObjectToReturnRepository repository; public ResponseEntity<Page<ObjectToReturn>> getObjectWithDynamicCriteria(Pageable pageable, @QuerydslPredicate(root = ObjectToReturn.class) Predicate predicate) { // 框架自动将前端动态参数转换为Predicate,分页参数由Pageable处理 Page<ObjectToReturn> resultPage = repository.findAll(predicate, pageable); return ResponseEntity.ok(resultPage); }
这种方式无需手动解析参数,适合复杂的动态查询场景。
内容的提问来源于stack exchange,提问作者BillUser88
相关产品推荐
相关产品推荐

