รับรายการของวัตถุ JSON ด้วย Spring RestTemplate


199

ฉันมีสองคำถาม:

  • วิธีแมปรายการของวัตถุ JSON โดยใช้ Spring RestTemplate
  • วิธีแมปออบเจ็กต์ JSON ที่ซ้อนกัน

ฉันพยายามที่จะกินhttps://bitpay.com/api/ratesโดยต่อไปนี้การกวดวิชาจากhttp://spring.io/guides/gs/consuming-rest/


2
ลองดูคำตอบนี้โดยเฉพาะถ้าคุณต้องการใช้รายการ generics 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()


มันใช้งานได้อย่างมีเสน่ห์ขอบคุณ บางทีคุณสามารถพาฉันไปที่แบบฝึกหัดหรือคำแนะนำอื่น ๆ ที่ฉันสามารถอ่านในหัวข้อนี้ได้?
Karudi

2
ดีที่สุดที่จะดูที่นี่ใน stackoverflow สำหรับตัวอย่างโค้ดและตัวอย่างหรือเยี่ยมชมเว็บไซต์ offial spring ...... TblGps [] a = responseEntity.getBody ();
kamokaze

เป็นไปได้ไหมถ้าใช้ยาชื่อสามัญ? นั่นคือวิธีการของฉันมีพารามิเตอร์ Class <T ขยาย Foo> และฉันต้องการรับชุด T จากเมธอด getForEntity
Diskutant

ใช่มันใช้งานได้ แต่อาจไม่ได้ออกนอกกรอบทั้งนี้ขึ้นอยู่กับรุ่นสปริง / แจ็คสันและประเภทคลาสของคุณ มันคือทั้งหมดที่เกี่ยวกับการทำให้เป็นอนุกรม / ข้อมูลทั่วไป - คำขอ HTTP นั้นไม่สนใจสิ่งที่ถูกขนส่ง
kamokaze


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

โซลูชันอื่น ๆ ด้านบนจะใช้งานได้เช่นกัน แต่ฉันชอบรับรายการที่พิมพ์กลับอย่างแรงแทนที่จะเป็นวัตถุ []


6
การดำเนินการนี้ราบรื่นกับ Spring 4.2.3 และ - ตามที่ Matt กล่าว - มีข้อได้เปรียบอย่างมากในการหลีกเลี่ยง Object []
Marged

@ Matt - marshaller ใดที่คุณใช้ในการจัด json ในวัตถุ Rate? ฉันเดาว่าเป็นสิ่งที่เกิดขึ้นที่นี่ในเวลาที่restTemplate.exchangemarshallar แมปค่า json ทั้งหมดกับชื่อคีย์ที่ตรงกันเป็นคุณสมบัติในวัตถุ Rate หวังว่ากระบวนการคิดของฉันจะถูกต้อง
Nirmal

สมบูรณ์แบบทำงานได้ดีใน Spring Boot 1.4.0 ปล่อยขอบคุณ
Anand

1
@Nirmal Spring ใช้ Jackson ตามค่าเริ่มต้นฉันเชื่อว่า
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)...)
Ruslan Stelmachenko

1
ที่บันทึกไว้ตูดของฉัน :) สงสัยว่าสิ่งที่ประเภทจะถูกใช้โดยแจ็คสันเมื่อระบุไว้ในวิธีการObject.class getForObject()
Eric Wang

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

ปัญหาใหญ่ของฉันที่นี่คือการสร้างโครงสร้างวัตถุที่ต้องการจับคู่ RestTemplate กับ Class ที่เข้ากันได้ โชคดีที่ฉันพบhttp://www.jsonschema2pojo.org/ (รับการตอบสนอง JSON ในเบราว์เซอร์และใช้เป็นอินพุต) และฉันไม่สามารถแนะนำสิ่งนี้ได้มากพอ!


2

ฉัน deveopped สิ่งที่ทำงานได้จริงสำหรับหนึ่งในโครงการของฉันก่อนและนี่คือรหัส:

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

หากคุณต้องการ List of Objects วิธีหนึ่งในการทำเช่นนี้คือ:

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 และเราไม่ต้องกังวลเกี่ยวกับการลบประเภทอีกต่อไป "



1

คุณสามารถสร้าง POJO สำหรับแต่ละรายการเช่น

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

จากนั้นใช้ ParameterizedTypeReference of List ของ 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 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ให้ข้อผิดพลาดในการรวบรวม "ประเภทที่เข้ากันไม่ได้"
Esko Luontola
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.