Nhận danh sách các đối tượng JSON với Spring RestTemplate


199

Tôi có hai câu hỏi:

  • Cách ánh xạ danh sách các đối tượng JSON bằng Spring RestTemplate.
  • Cách ánh xạ các đối tượng JSON lồng nhau.

Tôi đang cố gắng tiêu thụ https://bitpay.com/api/rates , bằng cách làm theo hướng dẫn từ http://spring.io/guides/gs/consuming-rest/ .


2
Xem xét xem câu trả lời này, đặc biệt nếu bạn muốn sử dụng danh sách
tổng quát

Câu trả lời:


220

Có lẽ theo cách này ...

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

Mã điều khiển cho RequestMapping

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

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

ResponseEntitylà một phần mở rộng HttpEntitythêm HttpStatusmã trạng thái. Được sử dụng trong các phương pháp RestTemplatelà tốt @Controller. Trong RestTemplatelớp này được trả lại bởi getForEntity()exchange().


Điều đó làm việc như một lá bùa, cảm ơn bạn. Có lẽ bạn có thể hướng tôi đến một số hướng dẫn hoặc hướng dẫn khác mà tôi có thể đọc về chủ đề này?
Karudi

2
tốt nhất để xem ở đây trên stackoverflow cho một số đoạn mã và ví dụ hoặc truy cập trang web mùa xuân chính thức ...... TblGps [] a = responsEntity.getBody ();
kamokaze

Có thể sử dụng thuốc generic này không? tức là phương thức của tôi có tham số Class <T mở rộng Foo> và tôi muốn nhận một bộ sưu tập T từ phương thức getForEntity.
Diskutant

Có, nó sẽ hoạt động, nhưng có thể không nằm ngoài hộp tùy thuộc vào phiên bản spring / jackson và các loại lớp của bạn. Đó là tất cả về khái quát hóa tuần tự hóa / khử lưu huỳnh - Yêu cầu http istelf không quan tâm những gì được vận chuyển.
kamokaze


335

Đầu tiên xác định một đối tượng để giữ thực thể quay trở lại trong mảng .. vd

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

Sau đó, bạn có thể sử dụng dịch vụ và nhận danh sách được gõ mạnh thông qua:

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

Các giải pháp khác ở trên cũng sẽ hoạt động, nhưng tôi thích lấy lại danh sách được gõ mạnh thay vì Object [].


6
Hoạt động này diễn ra suôn sẻ với Spring 4.2.3 và - như Matt đã nói - có lợi thế lớn là tránh đối tượng []
Marged

@Matt - bạn đang sử dụng marshaller nào để sắp xếp json thành các đối tượng Rate? Tôi đoán đó là những gì đang xảy ra ở đây, tại thời điểm restTemplate.exchangemột soái ca ánh xạ tất cả các giá trị json vào các tên khóa phù hợp làm thuộc tính trong đối tượng Rate. Hy vọng quá trình suy nghĩ của tôi là chính xác.
Nertal

Hoàn hảo, hoạt động tốt trong Spring Boot 1.4.0.RELEASE Cảm ơn
Anand

1
Tôi tin rằng @Nirmal Spring sử dụng Jackson theo mặc định.
Sohaib

1
@SarvarNishonboev các ParameterizedTypeReference hiện từ springframework.core vẫn có vẻ tốt đẹp: docs.spring.io/spring-framework/docs/current/javadoc-api/org/...
fspinnenhirn

75

Đối với tôi điều này đã làm việc

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

Trong đó Object là lớp bạn muốn


16
Điều này hoạt động ngay cả khi bạn sử dụng một lớp và không phải đối tượng nhưCoupon[] coupons = restTemplate.getForObject( url, Coupon[].class)
lrkwz

1
Điều này có thể gây ra NPE nếu phần thân phản hồi HTTP trống (không []nhưng hoàn toàn trống). Vì vậy, hãy cẩn thận và kiểm tra null( if (forNow != null)...).
Ruslan Stelmachenko

1
Đã lưu ass của tôi :) Tự hỏi loại nào được Jackson sử dụng, khi Object.classđược chỉ định trong phương thức getForObject().
Eric Wang

5

Sau nhiều thử nghiệm, đây là cách tốt nhất tôi tìm thấy :)

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

Tất cả bạn cần ở đó

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());
}

Lưu ý: điều này đòi hỏi ổi
vphilipnyc

2

Vấn đề lớn của tôi ở đây là xây dựng cấu trúc Object cần thiết để khớp RestTemplate với Class tương thích. May mắn thay, tôi đã tìm thấy http://www.jsonschema2pojo.org/ (nhận phản hồi JSON trong trình duyệt và sử dụng nó làm đầu vào) và tôi không thể khuyên bạn điều này đủ!


2

tôi thực sự đã phát hiện ra một cái gì đó có chức năng cho một trong các dự án của tôi trước đây và đây là mã:

/**
 * @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;
    }
}

Tôi hy vọng rằng điều này sẽ giúp được ai đó!


1

Nếu bạn muốn một Danh sách các Đối tượng, một cách để làm điều đó là như sau:

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;
}

Và sử dụng nó như vậy:

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

Giải thích cho những điều trên có thể được tìm thấy ở đây ( https://www.baeldung.com/spring-rest-template-list ) và được diễn giải dưới đây.

"Có một vài điều xảy ra trong đoạn mã ở trên. Đầu tiên, chúng tôi sử dụng FeedbackEntity làm kiểu trả về của chúng tôi, sử dụng nó để bọc danh sách các đối tượng chúng tôi thực sự muốn. Thứ hai, chúng tôi đang gọi RestTemplate.exchange () thay vì getForObject () .

Đây là cách chung nhất để sử dụng RestTemplate. Nó yêu cầu chúng tôi chỉ định phương thức HTTP, thân yêu cầu tùy chọn và loại phản hồi. Trong trường hợp này, chúng tôi sử dụng một lớp con ẩn danh của ParameterizedTypeReference cho loại phản hồi.

Phần cuối cùng này là những gì cho phép chúng ta chuyển đổi phản hồi JSON thành một danh sách các đối tượng là loại thích hợp. Khi chúng ta tạo một lớp con ẩn danh của ParameterizedTypeReference, nó sử dụng sự phản chiếu để nắm bắt thông tin về loại lớp mà chúng ta muốn chuyển đổi phản hồi của mình sang.

Nó giữ thông tin này bằng cách sử dụng đối tượng Type của Java và chúng tôi không còn phải lo lắng về việc xóa kiểu. "



1

Bạn có thể tạo POJO cho mỗi mục như,

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

sau đó sử dụng ParameterizedTypeReference of List of BitPay, bạn có thể sử dụng như:

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

Tôi tìm thấy công việc xung quanh từ bài đăng này https://jira.spring.io/browse/SPR-8263 .

Dựa trên bài đăng này, bạn có thể trả về một danh sách đánh máy như thế này:

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

4
Điều này sẽ không hoạt động, vì do xóa, không có thông tin tham số loại nào được truyền đến getForEntity. Cũng (Class<? extends ArrayList<User>>) ArrayList.classđưa ra một lỗi biên dịch "các loại không tương thích".
Esko Luontola
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.