我正在构建RESTful API,并希望为开发人员提供选择在JSON响应中返回哪些字段的选项。 This blog post显示了几个API(Google,Facebook,LinkedIn)如何允许开发人员自定义响应的示例。这被称为部分响应。
示例可能如下所示:
/users/123?fields=userId,fullname,title
在上面的示例中,API应返回User“123”的userId,fullName和title字段。
我正在寻找如何在我的RESTful Web服务中实现这一点的想法。我目前正在使用CXF(编辑:和杰克逊),但愿意尝试另一种JAX-RS实现。
这是我现在拥有的。它返回一个完整的User对象。如何根据“字段”参数返回API调用者在运行时所需的字段?我不想让其他字段为空。我根本不想归还他们。
@GET
@Path("/{userId}")
@Produces("application/json")
public User getUser(@PathParam("userId") Long userId,
@DefaultValue("userId,fullname,title") @QueryParam("fields") String fields) {
User user = userService.findOne(userId);
StringTokenizer st = new StringTokenizer(fields, ",");
while (st.hasMoreTokens()) {
// here's where i would like to select only the fields i want to return
}
return user;
}
更新
我关注了unludo的链接,然后链接到此:http://wiki.fasterxml.com/JacksonFeatureJsonFilter
通过该信息,我将@JsonFilter("myFilter")
添加到了我的域类。然后我修改了我的RESTful服务方法,返回String而不是User,如下所示:
@GET
@Path("/{userId}")
@Produces("application/json")
public String getUser(@PathParam("userId") Long userId,
@DefaultValue("userId,fullname,title") @QueryParam("fields") String fields) {
User user = userService.findOne(userId);
StringTokenizer st = new StringTokenizer(fields, ",");
Set<String> filterProperties = new HashSet<String>();
while (st.hasMoreTokens()) {
filterProperties.add(st.nextToken());
}
ObjectMapper mapper = new ObjectMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties));
try {
String json = mapper.filteredWriter(filters).writeValueAsString(user);
return json;
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
}
我需要做更多的测试,但到目前为止还不错。
答案 0 :(得分:18)
如果你使用Jackson(一个很棒的JSON lib - 我相信的Java标准),你可以使用@View
注释来过滤你想要的结果对象。
我知道你想要一些动态的东西,所以它有点复杂。您可以在此处找到所需内容:http://www.cowtowncoder.com/blog/archives/2011/02/entry_443.html(请参阅6.完全动态过滤:@JsonFilter
)。
我会对你会找到的解决方案感兴趣。
答案 1 :(得分:5)
在每个请求的资源方法内创建一个ObjectMapper实例可能会产生很大的性能开销。根据{{3}},对象映射器的创建成本很高。
相反,您可以使用the Jackson performance best practices在资源方法中自定义JAX-RS提供程序的Jackson对象编写器。
这是一个示例,说明如何注册ObjectWriterModifier线程本地对象,该对象更改为资源方法中使用的JAX-RS Jackson提供程序应用的过滤器集。请注意,我没有针对JAX-RS实现测试代码。
public class JacksonObjectWriterModifier2 {
private static class FilterModifier extends ObjectWriterModifier {
private final FilterProvider provider;
private FilterModifier(FilterProvider provider) {
this.provider = provider;
}
@Override
public ObjectWriter modify(EndpointConfigBase<?> endpoint, MultivaluedMap<String, Object> responseHeaders,
Object valueToWrite, ObjectWriter w, JsonGenerator g) throws IOException {
return w.with(provider);
}
}
@JsonFilter("filter1")
public static class Bean {
public final String field1;
public final String field2;
public Bean(String field1, String field2) {
this.field1 = field1;
this.field2 = field2;
}
}
public static void main(String[] args) throws IOException {
Bean b = new Bean("a", "b");
JacksonJsonProvider provider = new JacksonJsonProvider();
ObjectWriterInjector.set(new FilterModifier(new SimpleFilterProvider().addFilter("filter1",
SimpleBeanPropertyFilter.filterOutAllExcept("field1"))));
provider.writeTo(b, Bean.class, null, null, MediaType.APPLICATION_JSON_TYPE, null, System.out);
}
}
输出:
{"field1":"a"}
答案 2 :(得分:4)
The Library jersey-entity-filtering可以做到:
https://github.com/jersey/jersey/tree/2.22.2/examples/entity-filtering-selectable
https://jersey.java.net/documentation/latest/entity-filtering.html
例如:
我的对象
{
"streetAddress": "2 square Tyson",
"region": "Texas"
}
URL
人/ 1234?选择=的StreetAddress,区域
返回
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-entity-filtering</artifactId>
<version>2.22.2</version>
</dependency>
添加到Maven
window.passvariables = function(aControl, thissource) {
// Your code
};