2012-02-16 34 views
39

我构建了一个RESTful API,并希望为开发人员提供选项,以便选择在JSON响应中返回哪些字段。 This blog post显示了几个API(Google,Facebook,LinkedIn)允许开发人员定制响应的示例。这被称为部分响应。如何使用Java返回部分JSON响应?

一个例子可能是这样的:

/users/123?fields=userId,fullname,title 

在API上面的例子应该返回用户id,用户“123”全名和标题字段。

我正在寻找如何在我的REST风格的Web服务中实现这个想法。我目前正在使用CXF(编辑:和杰克逊),但愿意尝试另一个JAX-RS实现。

这是我目前有。它返回一个完整的用户对象。我怎样才能返回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; 
} 

UPDATE:

我跟着unludo的链接,再联系到这一点:http://wiki.fasterxml.com/JacksonFeatureJsonFilter

有了这些信息,我添加@JsonFilter("myFilter")我的领域类。然后我修改了RESTful服务方法返回一个字符串,而不是用户如下:

@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

如果我想让字段查询参数选项不区分大小写? – 2017-01-03 14:31:02

回答

17

如果您使用杰克逊(一个伟大的JSON库 - 一种Java的标准,我相信),您可以使用@View注释来过滤你想要的结果对象。

我知道你想要一些动态的东西,所以它有点复杂。你会发现你在找什么:http://www.cowtowncoder.com/blog/archives/2011/02/entry_443.html(看看6.完全动态过滤:@JsonFilter)。

我会感兴趣的解决方案,你会发现。

+0

如果我想让字段查询参数选项不区分大小写? – 2017-01-03 14:31:58

5

在资源方法中为每个请求创建一个ObjectMapper实例可能会产生显着的性能开销。根据the Jackson performance best practices对象映射器创建起来很昂贵。

相反,您可以使用the Jackson 2.3 ObjectWriterModifier/ObjectReaderModifier feature自定义资源方法内的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"} 
+0

如果我想让字段查询参数选项不区分大小写? – 2017-01-04 06:56:45

3

图书馆球衣实体过滤可以这样做:

https://github.com/jersey/jersey/tree/2.22.2/examples/entity-filtering-selectable

https://jersey.java.net/documentation/latest/entity-filtering.html

例:

我的目标

public class Address { 

    private String streetAddress; 
    private String region; 
    private PhoneNumber phoneNumber; 
} 

URL

人/ 1234?选择=的StreetAddress,区域

RETURN

{ 
    "streetAddress": "2 square Tyson", 
    "region": "Texas" 
} 

添加到Maven

<dependency> 
    <groupId>org.glassfish.jersey.ext</groupId> 
    <artifactId>jersey-entity-filtering</artifactId> 
    <version>2.22.2</version> 
</dependency> 
+0

Stack Overflow社区通常不赞同第三方库和插件的链接。 SO更适合获取代码示例以帮助您调试编程代码。但我喜欢你的答案的真棒格式。 – Kmeixner 2016-03-18 17:20:35

+0

如果我想让字段查询参数选项不区分大小写? – 2017-01-04 06:56:55