【问题标题】:How To Extract Data From JSON with Rest Template in Java如何使用 Java 中的 Rest 模板从 JSON 中提取数据
【发布时间】:2019-08-22 07:44:20
【问题描述】:

我必须从 https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=19acc3a371d145ecb37a093f9985ea21 中提取前 5 篇文章,结果如下:

{
    "total": 5,
    "articles": [
{
    "source": "Ilmessaggero.it",
    "title": "Title",
    "author": "Author",
    "url": "URL"
  }
 ]
}

我这样做了,将所有 JSON 作为字符串作为 localhost 的输出...

@RequestMapping("/news")
    public Article connection() {

        return restTemplate.getForObject
                ("https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=19acc3a371d145ecb37a093f9985ea21",  Article.class);

localhost 中的结果是:

{"source":null,"title":null,"author":null,"url":null}

但现在的问题是,如何将数据放入文章列表中? 以及如何将它们保存到 mongodb 中?感谢您的努力

【问题讨论】:

    标签: java mongodb resttemplate


    【解决方案1】:

    我解决了!简而言之,Article 的 NewsAPI json 有一个名为 Source 的字段,我试图将其解析为字符串,但事实并非如此!事实上,它是一个用另一个对象描述的场!我只需要创建一个带有 id 和名称的名为 Source 的类,它就可以工作了!感谢大家的努力!

    这是类的代码:

    public class Article {
    
        private Source source;
    
        private String author;
    
        private String title;
    
        private String url;
    
        //getters and setters
    

    News,其中有文章列表:

    public class News {
    
        private int totalResults;
    
        private List<Article> articles;
    
        //getters and setters
    

    和来源,在文章中被称为:

    public class Source {
    
        private String id;
    
        private String name;
    
        //getters and setters
    

    来了!解析代码与答案相同。只需将返回类型(Article)改成News,getForObject的Article.class参数改成News.class

    【讨论】:

      【解决方案2】:

      一种简单(即缺少异常处理等)的方式如下:

      首先,您需要一个类来表示您正在接收的数据,其字段与 API 响应字段匹配,例如:

      public class Article {
      
          private String source;
          private String title;
          ...  // more fields
      
         // getters and setters
      }
      

      从 API 获取数据的代码如下所示:

      RestTemplate template = ...  // initialized earlier
      ResponseEntity<Article[]> response = template.exchange(
          API_URL,  // url to the api
          HttpMethod.GET,  // use the Http verb "GET"
          new HttpEntity<>(headers),  // optional headers, e.g. for basic auth
          Article[].class  // the expected response type is Article[]
      );
      
      Article[] articles = response.getBody();
      List<Article> list = Arrays.asList(articles);  // if you need to use collections
      

      注意,ResponseEntity 为非 null 并不意味着请求成功。您可以使用responseEntity.getStatusCode() 来确定响应的状态码。

      但是要小心,因为默认情况下,RestTemplate 在收到非 200 错误代码时会引发异常(HttpClientErrorExceptionHttpServerErrorException 分别用于 4XX 和 5XX 代码)。如果您想要自己的自定义错误处理,您应该调用:

      template.setErrorHandler(new ResponseErrorHandler() {
          @Override
          public boolean hasError(ClientHttpResponse response) throws IOException {
              // implement here
          }
      
          @Override
          public void handleError(ClientHttpResponse response) throws IOException {
              // implement here
          }
      });
      

      对于 MongoDB 的持久性,您可以使用 JPA,尽管由于 JPA 固有的关系性质与 Mongo 的非关系结构发生冲突,因此 JPA 并不适合 MongoDB。像 Spring Data 这样的东西可以更明智地映射这一点,值得研究:https://spring.io/projects/spring-data-mongodb

      编辑 - 调用此代码

      通常,我将创建一个带有实现的类/接口(例如称为ArticleResource),如下所示:

      public class ArticleResource {
      
          private final RestTemplate template = new RestTemplate();
      
          public List<Article> getAllArticles() {
              ResponseEntity<Article[]> response = template.exchange(API_URL, HttpMethod.GET, new HttpEntity<>(headers), Article[].class);
      
          // some error checking here
      
          return response.getBody() == null ? Collections.emptyList() : Arrays.asList(response.getBody());
          }
      }
      

      对于需要单个值的方法(例如 findArticleByTitle(String title)),我通常会返回 Optional&lt;Article&gt;(返回 Optional&lt;List&lt;T&gt;&gt; 是不好的做法,因为空列表已经表示“没有值”)。

      您可以在代码中调用:

      ArticleResource resource = new ArticeResource();
      
      // if you want to print all the names for example:
      resource.getAllArticles().stream().map(Article::getName).forEach(System.out::println);
      

      【讨论】:

      • 对不起,我省略了文章类,我已经这样做了...现在我去更正帖子...无论如何我正在阅读这篇文章,似乎很清楚
      • 没问题,很高兴它看起来很有帮助:)
      • 最后一个问题,我返回的连接方式是什么?
      • 我只需要在 ResponseEntity
        response = template.exchange( etc etc etc 之前添加 return 吗?
      • 我得到 com.fasterxml.jackson.databind.exc.MismatchedInputException 的错误:无法从 [Source: (PushbackInputStream) 的 START_OBJECT 令牌中反序列化 com.kdmforce.testnewsexercise.models.Article[] 的实例;行:1,列:1]
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多