在Quarkus与Eclipse MicroProfile中复用REST API的@Header定义
解决方案
一、复用@Header配置数组
有两种实用方式可以避免重复编写分页相关的@Header配置:
1. 定义常量数组
先创建一个常量类,把分页响应头的OpenAPI配置封装成静态数组,后续直接引用即可:
public class OpenApiConstants { public static final Header[] PAGE_RESPONSE_HEADERS = { new Header() .name("X-Total-Count") .description("总对象数") .schema(new Schema().type(SchemaType.INTEGER)), new Header() .name("X-Offset") .description("当前偏移量") .schema(new Schema().type(SchemaType.INTEGER)), new Header() .name("X-Limit") .description("当前限制值") .schema(new Schema().type(SchemaType.INTEGER)) }; }
在接口方法的@APIResponse中直接使用这个常量数组:
@GET @APIResponse( responseCode = "200", description = "分页结果", headers = OpenApiConstants.PAGE_RESPONSE_HEADERS ) public List<Item> getItems(@QueryParam("offset") int offset, @QueryParam("limit") int limit) { // 业务逻辑实现 }
后续如果要调整头的命名或描述,只需要修改常量数组,所有引用的地方都会自动同步。
2. 自定义组合注解
利用Java的注解组合特性,创建一个包含所有分页头配置的自定义注解,替代重复的@Header数组:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) @APIResponse( responseCode = "200", headers = { @Header(name = "X-Total-Count", description = "总对象数", schema = @Schema(type = SchemaType.INTEGER)), @Header(name = "X-Offset", description = "当前偏移量", schema = @Schema(type = SchemaType.INTEGER)), @Header(name = "X-Limit", description = "当前限制值", schema = @Schema(type = SchemaType.INTEGER)) } ) public @interface PageableApiResponse {}
之后在接口方法上只需标记这个自定义注解即可:
@GET @PageableApiResponse public List<Item> getItems(@QueryParam("offset") int offset, @QueryParam("limit") int limit) { // 业务逻辑实现 }
这种方式更简洁,后期调整配置时只需要修改自定义注解的内容。
二、Quarkus中用响应头返回分页信息的标准化处理
如果不想在每个方法上手动配置OpenAPI注解,更高效的方案是通过JAX-RS ContainerResponseFilter统一处理分页响应头,无需重复代码:
- 先定义一个分页结果载体类,用来封装数据列表和分页元数据:
public class PageResult<T> { private List<T> data; private long totalCount; private int offset; private int limit; // 构造器、getter/setter方法 }
- 实现
ContainerResponseFilter,拦截返回PageResult的响应,自动添加分页头并替换响应体为数据列表:
@Provider public class PageResponseFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { Object entity = responseContext.getEntity(); if (entity instanceof PageResult<?>) { PageResult<?> pageResult = (PageResult<?>) entity; // 添加分页响应头 responseContext.getHeaders().add("X-Total-Count", pageResult.getTotalCount()); responseContext.getHeaders().add("X-Offset", pageResult.getOffset()); responseContext.getHeaders().add("X-Limit", pageResult.getLimit()); // 将响应体替换为实际数据列表,避免返回整个PageResult对象 responseContext.setEntity(pageResult.getData()); } } }
- 接口方法直接返回
PageResult,过滤器会自动处理响应头和响应体:
@GET public PageResult<Item> getItems(@QueryParam("offset") int offset, @QueryParam("limit") int limit) { List<Item> items = // 从数据源获取分页数据 long totalCount = // 查询总记录数 return new PageResult<>(items, totalCount, offset, limit); }
这种方式是Quarkus社区常用的实践,既符合RESTful设计(用响应头传递元数据),又能保证所有分页接口的格式统一。如果后续需要调整头的命名规则,只需修改过滤器中的头名称即可。
内容的提问来源于stack exchange,提问作者mitch-lbw
相关产品推荐
相关产品推荐

