2012-02-16 56 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