Получить список объектов 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 для некоторых фрагментов кода и примеров или посетить официальный сайт Spring ... TblGps [] a = responseEntity.getBody ();
Камоказе

Возможно ли это с помощью дженериков? То есть мой метод имеет параметр Class <T extends Foo>, и я хотел бы получить коллекцию T из метода getForEntity.
Дикутант

Да, это должно работать, но не может быть из коробки в зависимости от вашей версии Spring / Jackson и ваших классов. Все дело в сериализации / десериализации дженериков - запрос 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
Этот прогон прошел гладко с Spring 4.2.3 и - как сказал Мэтт - имеет большое преимущество в том, чтобы избегать Object []
Marged

@Matt - какой маршаллер вы используете для маршалинга json в объекты Rate? Я предполагаю, что это то, что здесь происходит, во время restTemplate.exchangeмаршаллар сопоставляет все значения json с соответствующими именами ключей как свойства в объекте Rate. Надеюсь, мой мыслительный процесс правильный.
Нирмал

Отлично, отлично работает в Spring Boot 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
Это работает, даже если вы используете класс, а не объект, какCoupon[] 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());
}

Примечание: для этого требуется Guava
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, он использует отражение для сбора информации о типе класса, в который мы хотим преобразовать наш ответ.

Он сохраняет эту информацию с помощью Java-объекта Type, и нам больше не нужно беспокоиться об удалении типов ».



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.