您可能想使用以下方法。这是一个非常符合标准的解决方案,其中没有任何技巧。上面的解决方案也可以工作,但有些不太正规,因为它只处理请求体,而是从上下文中提取数据。在我的情况下,我想创建一个注释,允许将查询参数“limit”和“offset”映射到单个对象。解决方案如下:
@Provider
public class SelectorParamValueFactoryProvider extends AbstractValueFactoryProvider {
public static final String OFFSET_PARAM = "offset";
public static final String LIMIT_PARAM = "limit";
@Singleton
public static final class InjectionResolver extends ParamInjectionResolver<SelectorParam> {
public InjectionResolver() {
super(SelectorParamValueFactoryProvider.class);
}
}
private static final class SelectorParamValueFactory extends AbstractContainerRequestValueFactory<Selector> {
@Context
private ResourceContext context;
private Parameter parameter;
public SelectorParamValueFactory(Parameter parameter) {
this.parameter = parameter;
}
public Selector provide() {
UriInfo uriInfo = context.getResource(UriInfo.class);
MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
SelectorParam selectorParam = parameter.getAnnotation(SelectorParam.class);
long offset = selectorParam.defaultOffset();
if(params.containsKey(OFFSET_PARAM)) {
String offsetString = params.getFirst(OFFSET_PARAM);
offset = Long.parseLong(offsetString);
}
int limit = selectorParam.defaultLimit();
if(params.containsKey(LIMIT_PARAM)) {
String limitString = params.getFirst(LIMIT_PARAM);
limit = Integer.parseInt(limitString);
}
return new BookmarkSelector(offset, limit);
}
}
@Inject
public SelectorParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator injector) {
super(mpep, injector, Parameter.Source.UNKNOWN);
}
@Override
public AbstractContainerRequestValueFactory<?> createValueFactory(Parameter parameter) {
Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(Selector.class))) {
return null;
}
return new SelectorParamValueFactory(parameter);
}
}
你还需要做的是注册它。
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
register(JacksonFeature.class);
register(new InjectionBinder());
}
private static final class InjectionBinder extends AbstractBinder {
@Override
protected void configure() {
bind(SelectorParamValueFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
bind(SelectorParamValueFactoryProvider.InjectionResolver.class).to(
new TypeLiteral<InjectionResolver<SelectorParam>>() {
}).in(Singleton.class);
}
}
}
您需要的注释本身也很重要。
@Target({java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD})
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface SelectorParam {
long defaultOffset() default 0;
int defaultLimit() default 25;
}
和一颗豆子
public class BookmarkSelector implements Bookmark, Selector {
private long offset;
private int limit;
public BookmarkSelector(long offset, int limit) {
this.offset = offset;
this.limit = limit;
}
@Override
public long getOffset() {
return 0;
}
@Override
public int getLimit() {
return 0;
}
@Override
public boolean matches(Object object) {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BookmarkSelector that = (BookmarkSelector) o;
if (limit != that.limit) return false;
if (offset != that.offset) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (offset ^ (offset >>> 32));
result = 31 * result + limit;
return result;
}
}
然后你可以像这样使用它。
@GET
@Path(GET_ONE)
public SingleResult<ItemDTO> getOne(@NotNull @PathParam(ID_PARAM) String itemId, @SelectorParam Selector selector) {
Item item = auditService.getOneItem(ItemId.create(itemId));
return singleResult(mapOne(Item.class, ItemDTO.class).select(selector).using(item));
}
BeanParam
。 - Patrick