我有一些资源句柄方法,其中包含许多@QueryParam
参数和@Default
,大致分为主题(分页/排序,过滤,身份验证)。这真的很麻烦,我想简化这个。好处是这些参数按主题分组(分页,排序,过滤等),所以我可以将整个参数集减少到4种方法。
我怎样才能做到这一点?
通常情况下,我想来自这个:
@GET
public Response findAll(
@QueryParam("sort") @DefaultValue("name") List<String> sort,
@QueryParam("from") UUID fromId
) {
// Validate sort
// Validate fromId
}
对此:
@GET
public Response findAll(@Context Pagination pagination) { // Inject pagination
// Yeah, small code! Yeah, modularity!
}
// Create the pagination somewhere else.
public Pagination createPagination(@Context UriInfo uriInfo) {
Optional<UUID> fromId = extractFromId(uriInfo); // retrieve "from" from uriInfo
List<String> sort = extractSort(uriInfo); // retrieve "sort" from uriInfo
Pagination pagination = new Pagination();
pagination.setFromId(fromId);
pagination.setSort(sort);
// Validate pagination
return pagination;
}
注意:正如我在我的示例中所示,我不介意自己编写更多代码,但我不能在我的方法中承担太多参数并阅读@QueryParam
的隔离墙+ @DefaultValue
。
答案 0 :(得分:4)
如果您使用的是JAX-RS 2.0,则可以使用@BeanParam
,它允许您将任意@XxxParam
带注释的属性和@Context
对象注入任意bean类。例如
public class Bean {
@QueryParam("blah")
String blah;
}
@GET
public Response get(@BeanParam Bean bean) {}
如果你想要不可移植性,你甚至可以注入构造函数。例如
public static class Pagination {
private final List<String> sort;
private final Optional<String> from;
public Pagination(@QueryParam("sort") List<String> sort,
@QueryParam("from") Optional<String> from) {
this.sort = sort;
this.from = from;
}
public List<String> getSort() { return sort; }
public Optional<String> getFrom() { return from; }
}
如果您注意到正在注射Optional
。通常情况下这是不可能的,但我为它创建了一个ParamConverter
。您可以在this answer中详细了解相关信息。它基本上允许我们注入任意对象,从参数的String值创建。
@Provider
public static class OptionalParamProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(Class<T> rawType,
Type genericType,
Annotation[] annotations) {
if (Optional.class != rawType) {
return null;
}
return (ParamConverter<T>)new ParamConverter<Optional>() {
@Override
public Optional fromString(String value) {
return Optional.ofNullable(value);
}
@Override
public String toString(Optional value) {
return value.toString();
}
};
}
}
OptionalParamProvider
的好处是,它允许您在任何需要注入Optional
,@FormParam
,@QueryParam
和所有内容的地方使用@PathParm
其他@XxxParam
s(多部分除外)。
我不知道您正在使用的JAX-RS实现,但上述内容应适用于所有实现。以下是使用Jersey Test Framework的Jersey测试用例。您可以像任何其他JUnit测试一样运行该类。
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Optional;
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import org.junit.Test;
public class BeanParamTest extends JerseyTest {
@Provider
public static class OptionalParamProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(Class<T> rawType,
Type genericType,
Annotation[] annotations) {
if (Optional.class != rawType) {
return null;
}
return (ParamConverter<T>)new ParamConverter<Optional>() {
@Override
public Optional fromString(String value) {
return Optional.ofNullable(value);
}
@Override
public String toString(Optional value) {
return value.toString();
}
};
}
}
public static class Pagination {
private final List<String> sort;
private final Optional<String> from;
public Pagination(@QueryParam("sort") List<String> sort,
@QueryParam("from") Optional<String> from) {
this.sort = sort;
this.from = from;
}
public List<String> getSort() { return sort; }
public Optional<String> getFrom() { return from; }
}
@Path("bean")
public static class PaginationResource {
@GET
public String get(@BeanParam Pagination pagination) {
StringBuilder sb = new StringBuilder();
sb.append(pagination.getSort().toString());
if (pagination.getFrom().isPresent()) {
sb.append(pagination.getFrom().get());
}
return sb.toString();
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(PaginationResource.class)
.register(OptionalParamProvider.class);
}
@Test
public void should_return_all_sort_and_from() {
Response response = target("bean")
.queryParam("sort", "foo")
.queryParam("sort", "bar")
.queryParam("from", "baz")
.request().get();
assertEquals(200, response.getStatus());
String message = response.readEntity(String.class);
assertThat(message, containsString("foo"));
assertThat(message, containsString("bar"));
assertThat(message, containsString("baz"));
System.out.println(message);
response.close();
}
}
这是运行测试所需的唯一Maven依赖
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.19</version>
<scope>test</scope>
</dependency>