Это ответ, который я получаю от API.
{"получить":"статистика","параметры":{"страна":"румыния"},"ошибки":[],"результаты":1,"ответ":[{"континент":"Европа", «страна»: «Румыния», «население»: 19016885, «случаи»: {«новые»: «+4521», «активные»: 156487, «критические»: 431, «выздоровевшие»: 2606660, «1M_pop»: "148707","всего":2827936},"смертей":{"новых":"+35","1M_pop":"3407","всего":64789},"испытаний":{"1M_pop":" 1149381","всего":21857638},"день":"2022-03-24","время":"2022-03-24T07:30:04+00:00"}]}
@RestController
public class CovidTrackerRestController {
@GetMapping("/hello")
public String showCovidInformation() {
// connect to a covid database
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://covid-193.p.rapidapi.com/statistics?country=romania"))
.header("X-RapidAPI-Host", "covid-193.p.rapidapi.com")
.header("X-RapidAPI-Key", "mykey")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = null;
try {
response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// get the information
String responseString = response.body();
System.out.println(responseString);
Response romaniaData = null;
try {
romaniaData = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.readValue(responseString, Response.class);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// format the information
System.out.println(romaniaData);
// send the information to html page
return "/tracker";
}
}
И это мой класс Bean, который помечен @Bean в классе конфигуратора рядом с bean-компонентом RestTemplate. Другие свойства, такие как Cases, Deaths и т. д., настраиваются так же, как класс Response, за исключением того, что они объявляются как @Bean в конфигураторе, потому что, насколько я знаю, как только я объявляю класс @Bean, другие содержащиеся ссылки также автоматически становятся bean-компонентами.
@JsonIgnoreProperties(ignoreUnknown = true)
public class Response {
@JsonProperty("country")
private String country;
@JsonProperty("cases")
private Cases cases;
@JsonProperty("deaths")
private Deaths deaths;
@JsonProperty("day")
private String day;
@JsonProperty("time")
private String time;
@JsonProperty("test")
private Tests tests;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@DanSerb ох, хороший улов! Забыл про ключ.
Класс ответа должен быть POJO, зачем вам вводить это с помощью @Autowired? Классы, используемые для хранения сущностей или, в данном случае, ответа, не должны быть bean-компонентами, вы должны создавать экземпляры для каждого вызова API, поэтому он должен быть членом фактического метода, а не класса. Вам не нужно объявлять эти классы как bean-компоненты.
Строка @Autowired осталась с предыдущей попытки, я забыл ее удалить. Я переназначил ссылку romaniaData на нулевое значение ниже и создал экземпляр в блоке try. Я отредактировал вопрос, чтобы удалить 2 боба. Результат, во всяком случае, тот же.
Ваш Response — это только часть всего ответа, который вы получаете от API. Он представляет только один элемент в свойстве response (который также является массивом) в json, а не весь json.
Кстати, ваш ключ API все еще можно увидеть в истории сообщений. Думаю лучше будет поменять.
@Chaosfire спасибо, я изменил его и удалил старый. Не могли бы вы посоветовать в ответе, как подойти к настройке? Я впервые пробую такое приложение после прохождения курса Spring Boot, и я не знаю, что делать дальше. В течение последних нескольких дней проводились исследования, но нет соответствующих ресурсов о том, как использовать внешние API, кроме как из файлов CSV.




Ваш класс Java должен быть точным представлением полученного json. Назовем это Wrapper:
public class Wrapper {
@JsonProperty("response")
private List<Response> responses;
public List<Response> getResponses() {
return this.responses;
}
public void setResponses(List<Response> responses) {
this.responses = responses;
}
@Override
public String toString() {
return "Wrapper{" +
"responses = " + responses +
'}';
}
}
Я опускаю некоторые свойства - get, results и т. д. Похоже, они вам не нужны. Тогда десериализация будет выглядеть так:
Wrapper data = null;
try {
data = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.readValue("json", Wrapper.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(data);
Несколько заметок:
@JsonPropertytests, а не testЕсли вы действительно хотите выбросить остальные данные и вам нужно только свойство response, вам нужно написать собственный десериализатор и работать с деревом json. Вы можете увидеть, как это сделать, например, в мой ответ здесь или это руководство. Таким образом вы можете разобрать ответ json на свой класс, даже если их структуры не совпадают.
ДА это сработало! Большое спасибо, я работал над этим последние 2 дня, не могу поверить, что это действительно сработало! Я вижу, что мне нужно научиться сопоставлять многоуровневые jsons с pojo. Любые рекомендации по ресурсам для этого?
Ну и дела @Chaosfire, мы дали очень похожие ответы почти в одно и то же время. +1 тебе от меня
@Art Я не знаю о таких ресурсах, для меня это была в основном практика. Вы можете попробовать спрятаться в тегах сериализации и десериализации и попытаться исследовать и ответить на вопросы, я узнал несколько вещей, отвечая.
@MichaelGantman Ха-ха, да, иногда такое случается :)
Да, ваш класс должен быть таким:
public class ResponseWrapper {
public List<Response> response;
public setResponse(List<Response> response) {
this.response= response;
}
public List<Response> getResponse() {
return response;
}
}
А класс Response — это ваш класс, как вы его опубликовали. Ваш класс должен иметь ту же структуру, что и JSON.
Ответ представляет собой массив в json, так работать не будет.
вы правы, поэтому свойство должно быть списком. изменение ответа
Прежде всего, вы не должны помещать ключи API в вопросы о переполнении стека.