使用Java调用REST API和解析JSON数据的最简单方法



我正在尝试做一些在javaScript中微不足道的事情,但Java似乎很复杂。我希望有人也可以在Java中指出如何做。

我想打电话给休息json api,例如https://images-api.nasa.gov/search?q=clouds

我获得了一个数据结构,以简化的形式看起来像这样:

{
  "collection": {
    "items": [
      {
        "links": [
          {
            "href": "https://images-assets.nasa.gov/image/cloud-vortices_22531636120_o/cloud-vortices_22531636120_o~thumb.jpg",
            "rel": "preview"
          }
        ]
      }
    ]
  }
}

在Java中,我想打电话给URL并将href字符串作为列表。

在JavaScript中,我只需写

fetch("https://images-api.nasa.gov/search?q=moon")
  .then(data => data.json())
  .then(data => {
    const items = data
      .collection
      .items
      .map(item => item.links)
      .flat()
      .filter(link => link.rel === "preview")
      .map(link => link.href);
    // do something with "items"
})

1。我的最初解决方案

稍作搜索,我找到了这种方法,它似乎朝着正确的方向发展,但仍然非常详细。

String uri = "https://images-api.nasa.gov/search?q=clouds";
List<String> hrefs = new ArrayList<>();
try {
    // make the GET request
    URLConnection request = new URL(uri).openConnection();
    request.connect();
    InputStreamReader inputStreamReader = new InputStreamReader((InputStream) request.getContent());
    // map to GSON objects
    JsonElement root = new JsonParser().parse(inputStreamReader);
    // traverse the JSON data 
    JsonArray items = root
            .getAsJsonObject()
            .get("collection").getAsJsonObject()
            .get("items").getAsJsonArray();
    // flatten nested arrays
    JsonArray links = new JsonArray();
    items.forEach(item -> links.addAll(item
            .getAsJsonObject()
            .get("links")
            .getAsJsonArray()));
    // filter links with "href" properties
    links.forEach(link -> {
        JsonObject linkObject = link.getAsJsonObject();
        String relString = linkObject.get("rel").getAsString();
        if ("preview".equals(relString)) {
            hrefs.add(linkObject.get("href").getAsString());
        }
    });
} catch (IOException e) {
    e.printStackTrace();
}
return hrefs;

我剩下的问题是:

  • 有办法使用RESTTEMPLATE或其他一些库来减少获取请求冗长,仍然保持GSON的通用灵活性?
  • 是否有一种方法可以使嵌套的jsonarrays和/或GSON与/或过滤创建其他临时jsonarrays?
  • 还有其他方法可以使代码少详细吗?

编辑

阅读下面的评论和答案后,添加了以下各节。


2。更少的详细解决方案

(如@diutsu的答案中提出的(

List<String> hrefs = new ArrayList<>();
String json = new RestTemplate().getForObject("https://images-api.nasa.gov/search?q=clouds", String.class);
new JsonParser().parse(json).getAsJsonObject()
    .get("collection").getAsJsonObject()
    .get("items").getAsJsonArray()
    .forEach(item -> item.getAsJsonObject()
        .get("links").getAsJsonArray()
        .forEach(link -> {
            JsonObject linkObject = link.getAsJsonObject();
            String relString = linkObject.get("rel").getAsString();
            if ("preview".equals(relString)) {
                hrefs.add(linkObject.get("href").getAsString());
            }
        })
    );
return hrefs;

3。使用mapper pojos

的解决方案

(受@jbnizet和@diutsu的启发(

Actuall获取请求和Tranformation现在是一个单线,几乎与我上面提出的JavaScript代码相同,...

return new RestTemplate().getForObject("https://images-api.nasa.gov/search?q=clouds", CollectionWrapper.class)
    .getCollection()
    .getItems().stream()
    .map(Item::getLinks)
    .flatMap(List::stream)
    .filter(item -> "preview".equals(item.getRel()))
    .map(Link::getHref)
    .collect(Collectors.toList());

...但是为了使我不得不创建以下4个类:

CollectionWrapper

public class CollectionWrapper {
    private Collection collection;
    public CollectionWrapper(){}
    public CollectionWrapper(Collection collection) {
        this.collection = collection;
    }
    public Collection getCollection() {
        return collection;
    }
}

收集

public class Collection {
    private List<Item> items;
    public Collection(){}
    public Collection(List<Item> items) {
        this.items = items;
    }
    public List<Item> getItems() {
        return items;
    }
}

项目

public class Item {
    private List<Link> links;
    public Item(){}
    public Item(List<Link> links) {
        this.links = links;
    }
    public List<Link> getLinks() {
        return links;
    }
}

链接

public class Link {
    private String href;
    private String rel;
    public Link() {}
    public Link(String href, String rel) {
        this.href = href;
        this.rel = rel;
    }
    public String getHref() {
        return href;
    }
    public String getRel() {
        return rel;
    }
}

4。使用kotlin

(受@nbnizet的启发(

val collectionWrapper = RestTemplate().getForObject("https://images-api.nasa.gov/search?q=clouds", CollectionWrapper::class.java);
return collectionWrapper
        ?.collection
        ?.items
        ?.map { item -> item.links }
        ?.flatten()
        ?.filter { item -> "preview".equals(item.rel) }
        ?.map { item -> item.href }
        .orEmpty()

使用kotlin使映射类别更简单,甚至比使用lombok

使用Java更简单
data class CollectionWrapper(val collection: Collection)
data class Collection(val items: List<Item>)
data class Item(val links: List<Link>)
data class Link(val rel: String, val href: String)

5。直接映射到地图和列表

我不相信这是一个好主意,但是很高兴知道可以做到:

return 
    ( (Map<String, Map<String, List<Map<String, List<Map<String, String>>>>>>) 
        new RestTemplate()
        .getForObject("https://images-api.nasa.gov/search?q=clouds", Map.class)
    )
    .get("collection")
    .get("items").stream()
    .map(item -> item.get("links"))
    .flatMap(List::stream)
    .filter(link -> "preview".equals(link.get("rel")))
    .map(link -> link.get("href"))
    .collect(Collectors.toList());

1(作为字符串

获取
restTemplate.getForObject("https://images-api.nasa.gov/search?q=clouds", String.class)

2(简单,不要使用数组。我会说它不太可读,但是您可以提取一些方法来帮助您。

root.getAsJsonObject()
    .get("collection").getAsJsonObject()
    .get("items").getAsJsonArray()
    .forEach(item -> item.getAsJsonObject()
       .get("links").getAsJsonArray()
       .forEach(link -> {
            JsonObject linkObject = link.getAsJsonObject();
            String relString = linkObject.get("rel").getAsString();
            if ("preview".equals(relString)) {
               hrefs.add(linkObject.get("href").getAsString());
            }));

3(如果您不要保持简单:d可以定义自己的结构,然后直接从RESTTEMPLATE到达该结构。这将是一个衬里。但是,由于您只关心HREF,因此没有意义。

最新更新