Отримайте список об’єктів JSON за допомогою Spring RestTemplate


199

У мене є два питання:

  • Як зіставити список об’єктів JSON за допомогою Spring RestTemplate.
  • Як зіставити вкладені об'єкти JSON.

Я намагаюся споживати https://bitpay.com/api/rates , дотримуючись підручника від http://spring.io/guides/gs/consuming-rest/ .


2
Розглянемо побачити цю відповідь, особливо якщо ви хочете використовувати список дженериків stackoverflow.com/questions/36915823 / ...
Moesio

Відповіді:


220

Можливо, таким чином ...

ResponseEntity<Object[]> responseEntity = restTemplate.getForEntity(urlGETList, Object[].class);
Object[] objects = responseEntity.getBody();
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();

Код контролера для RequestMapping

@RequestMapping(value="/Object/getList/", method=RequestMethod.GET)
public @ResponseBody List<Object> findAllObjects() {

    List<Object> objects = new ArrayList<Object>();
    return objects;
}

ResponseEntityє розширенням, HttpEntityщо додає HttpStatusкод статусу. Використовується RestTemplateтакож в @Controllerметодах. У RestTemplateцей клас повертається getForEntity()і exchange().


Це спрацювало як шарм, дякую. Можливо, ви можете направити мене на якісь інші підручники чи посібники, які я міг прочитати на цю тему?
Каруді

2
найкраще подивитися тут на stackoverflow для деяких фрагментів коду та прикладів або відвідати офіційний весняний веб-сайт ...... TblGps [] a = responseEntity.getBody ();
камокадзе

Чи можливо це зробити за допомогою дженериків? тобто мій метод має параметр Class <T extends Foo>, і я хотів би отримати колекцію T від методу getForEntity.
Дискутант

Так, це має спрацювати, але може не вийти з коробки залежно від вашої версії весна / Джексон та типу вашого класу. Все про серіалізацію / дезариалізацію дженериків - http-Запит себе не хвилює, що транспортується.
камокадзе


335

Спочатку визначте об'єкт для утримання об'єкта, що повертається в масив .. Наприклад

@JsonIgnoreProperties(ignoreUnknown = true)
public class Rate {
    private String name;
    private String code;
    private Double rate;
    // add getters and setters
}

Тоді ви можете скористатись послугою та отримати список, який набирається дуже сильно:

ResponseEntity<List<Rate>> rateResponse =
        restTemplate.exchange("https://bitpay.com/api/rates",
                    HttpMethod.GET, null, new ParameterizedTypeReference<List<Rate>>() {
            });
List<Rate> rates = rateResponse.getBody();

Інші рішення, наведені вище, також працюватимуть, але мені подобається повернення сильно набраного списку замість Object [].


6
Цей пробіг протікає з весною 4.2.3 і - як сказав Метт - має велику перевагу уникнути Об'єкта []
Мардж

@Matt - який маршал ви використовуєте, щоб перевести json в об'єкти Rate? Я здогадуюсь, що це відбувається тут під час restTemplate.exchangeмаршаллярного відображення всіх значень json на відповідні імена ключів як властивості об'єкта Rate. Сподіваюся, мій процес думки правильний.
Nirmal

Ідеально, чудово працює у весняному завантаженні 1.4.0. РЕЛІЗАЦІЯ Дякую
Ананд

1
@Nirmal Spring використовує Джексона за замовчуванням, я вважаю.
Sohaib

1
@SarvarNishonboev поточний ParameterizedTypeReference з springframework.core все ще здається нормальним: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
fspinnenhirn

75

Для мене це спрацювало

Object[] forNow = template.getForObject("URL", Object[].class);
    searchList= Arrays.asList(forNow);

Де Object - клас, який ви хочете


16
Це працює навіть у тому випадку, якщо ви використовуєте клас, а не Object likeCoupon[] coupons = restTemplate.getForObject( url, Coupon[].class)
lrkwz

1
Це може спричинити NPE, якщо тіло відповіді HTTP було порожнім (не []але повністю порожнім). Тож будьте уважні та перевірте наявність null( if (forNow != null)...).
Руслан Стельмаченко

1
Врятувало мою дупу :) Цікаво, який тип використовує Джексон, коли Object.classвказано у методі getForObject().
Ерік Ван

5

Після декількох тестів це найкращий спосіб, який я знайшов :)

Set<User> test = httpService.get(url).toResponseSet(User[].class);

Все, що вам там потрібно

public <T> Set<T> toResponseSet(Class<T[]> setType) {
    HttpEntity<?> body = new HttpEntity<>(objectBody, headers);
    ResponseEntity<T[]> response = template.exchange(url, method, body, setType);
    return Sets.newHashSet(response.getBody());
}

Примітка: для цього потрібна Гуава
vphilipnyc

2

Моя велика проблема тут полягала у створенні структури Object, необхідної для відповідності RestTemplate сумісному класу. На щастя, я знайшов http://www.jsonschema2pojo.org/ (отримайте відповідь JSON у веб-переглядачі та використовуйте її як вхід), і я не можу цього рекомендувати достатньо!


2

я фактично розробив щось функціональне для одного з моїх проектів раніше, і ось код:

/**
 * @param url             is the URI address of the WebService
 * @param parameterObject the object where all parameters are passed.
 * @param returnType      the return type you are expecting. Exemple : someClass.class
 */

public static <T> T getObject(String url, Object parameterObject, Class<T> returnType) {
    try {
        ResponseEntity<T> res;
        ObjectMapper mapper = new ObjectMapper();
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
        ((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setConnectTimeout(2000);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<T> entity = new HttpEntity<T>((T) parameterObject, headers);
        String json = mapper.writeValueAsString(restTemplate.exchange(url, org.springframework.http.HttpMethod.POST, entity, returnType).getBody());
        return new Gson().fromJson(json, returnType);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

/**
 * @param url             is the URI address of the WebService
 * @param parameterObject the object where all parameters are passed.
 * @param returnType      the type of the returned object. Must be an array. Exemple : someClass[].class
 */
public static <T> List<T> getListOfObjects(String url, Object parameterObject, Class<T[]> returnType) {
    try {
        ObjectMapper mapper = new ObjectMapper();
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
        ((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setConnectTimeout(2000);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<T> entity = new HttpEntity<T>((T) parameterObject, headers);
        ResponseEntity<Object[]> results = restTemplate.exchange(url, org.springframework.http.HttpMethod.POST, entity, Object[].class);
        String json = mapper.writeValueAsString(results.getBody());
        T[] arr = new Gson().fromJson(json, returnType);
        return Arrays.asList(arr);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

Я сподіваюся, що це комусь допоможе!


1

Якщо ви віддаєте перевагу списку об’єктів, один із способів зробити це такий:

public <T> List<T> getApi(final String path, final HttpMethod method) {     
    final RestTemplate restTemplate = new RestTemplate();
    final ResponseEntity<List<T>> response = restTemplate.exchange(
      path,
      method,
      null,
      new ParameterizedTypeReference<List<T>>(){});
    List<T> list = response.getBody();
    return list;
}

І використовуйте його так:

 List<SomeObject> list = someService.getApi("http://localhost:8080/some/api",HttpMethod.GET);

Пояснення вищесказаного можна знайти тут ( https://www.baeldung.com/spring-rest-template-list ) і перефразоване нижче.

"У наведеному вище коді відбувається кілька речей. По-перше, ми використовуємо ResponseEntity як наш тип повернення, використовуючи його для обгортання списку об'єктів, які нам дуже потрібні. По-друге, ми викликаємо RestTemplate.exchange () замість getForObject () .

Це найзагальніший спосіб використання RestTemplate. Він вимагає від нас вказати метод HTTP, необов'язковий орган запиту та тип відповіді. У цьому випадку ми використовуємо анонімний підклас ParameterizedTypeReference для типу відповіді.

Остання частина - це те, що дозволяє нам перетворити відповідь JSON у список об'єктів відповідного типу. Коли ми створюємо анонімний підклас ParameterizedTypeReference, він використовує відображення для збору інформації про тип класу, в який ми хочемо перетворити свою відповідь.

Він утримує цю інформацію за допомогою об’єкта Type Java, і нам більше не потрібно турбуватися про стирання типу ".



1

Ви можете створити POJO для кожного запису, наприклад,

class BitPay{
private String code;
private String name;
private double rate;
}

потім, використовуючи ParameterizedTypeReference списку BitPay, ви можете використовувати як:

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<Employee>> response = restTemplate.exchange(
  "https://bitpay.com/api/rates",
  HttpMethod.GET,
  null,
  new ParameterizedTypeReference<List<BitPay>>(){});
List<Employee> employees = response.getBody();

-1

Я знайшов роботу з цієї публікації https://jira.spring.io/browse/SPR-8263 .

На основі цієї публікації ви можете повернути такий тип тексту:

ResponseEntity<? extends ArrayList<User>> responseEntity = restTemplate.getForEntity(restEndPointUrl, (Class<? extends ArrayList<User>>)ArrayList.class, userId);

4
Це не спрацює, оскільки через стирання не передається інформація про параметри типу getForEntity. Також (Class<? extends ArrayList<User>>) ArrayList.classдає помилку компіляції "несумісних типів".
Еско Луонтола
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.