使用Spring RestTemplate获取JSON对象列表

248

2
如果您想使用泛型列表,请考虑查看此答案: https://dev59.com/w1oU5IYBdhLWcg3w9KPq#53398952 - Moesio
15个回答

408

首先定义一个对象来保存返回数组中的实体,例如:

@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上运行顺利,正如Matt所说,最大的优点是避免了使用Object[]。 - Marged
@Matt - 你在使用哪个marshaller将json转换为Rate对象?我猜这就是发生的事情,在restTemplate.exchange时,marshaller将所有json值映射到Rate对象中匹配的键名属性上。希望我的思路是正确的。 - Nirmal
1
@Nirmal Spring 默认使用 Jackson。 - Sohaib
2
ParameterizedTypeReference已被弃用。 - Sarvar Nishonboyev
1
@SarvarNishonboev,来自springframework.core的当前ParameterizedTypeReference看起来仍然很好:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/ParameterizedTypeReference.html - fspinnenhirn

252

也许这样会更好...

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

ResponseEntityHttpEntity的扩展,它添加了一个HttpStatus状态码。在RestTemplate@Controller方法中使用。 在RestTemplate中,getForEntity()exchange()方法返回此类。


那个方法非常有效,谢谢。也许你可以指导我阅读一些关于这个主题的其他教程或指南吗? - Karudi
2
最好在StackOverflow上查找一些代码片段和示例,或者访问官方Spring网站...... TblGps[] a = responseEntity.getBody(); - kamokaze
1
可以使用泛型来实现吗?例如,我的方法有一个 Class<T extends Foo> 参数,并且我想从 getForEntity 方法中获取 T 的集合。 - MetalSnake
是的,它应该可以工作,但根据您的Spring/Jackson版本和类类型,可能不会开箱即用。这一切都与泛型的序列化/反序列化有关 - http请求本身并不关心传输的内容。 - kamokaze
1
还可以参见http://forum.spring.io/forum/spring-projects/android/125835-how-to-get-a-list-myobject-via-resttemplate。 - Benny Bottema
@kamokaze,请您能否看一下这个相关的问题stackoverflow.com/q/48230251/2674303? - gstackoverflow

82

对我来说这个有效

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

Object是你想要的类


17
即使你使用类而不是Object,例如Coupon[] coupons = restTemplate.getForObject(url, Coupon[].class),这个方法也能正常工作。 - lrkwz
1
如果HTTP响应体为空(不是[]而是完全为空),这可能会导致NPE。因此要小心并检查null(if (forNow != null)...)。 - Ruslan Stelmachenko
1
救了我的命 :) 想知道在getForObject()方法中指定Object.class时,Jackson使用的是哪种类型。 - Eric

10
如果您希望得到一个POJO列表,可以通过以下方式实现:
class SomeObject {
    private int id;
    private String name;
}


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对象保存这些信息,我们不再需要担心类型擦除。


9
你可以为每个条目创建一个POJO,例如:
class BitPay{
private String code;
private String name;
private double rate;
}

然后使用ParameterizedTypeReference将BitPay的List作为参数,您可以这样使用:

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

7

如果您正在使用Spring + Kotlin进行开发,以下是翻译内容:

val rates = restTemplate.exchange("https://bitpay.com/api/rates", HttpMethod.GET, null, object : ParameterizedTypeReference<List<Rate>>() {}).body!!

2
在 Kotlin 中的另一种方法是这样做: val rates = restTemplate.exchange("https://bitpay.com/api/rates", HttpMethod.GET, null, Array<Rate>::class.java).body!! - DagR

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库。 - riddle_me_this

4

这里提到了三种检索对象列表的替代方法。所有这些方法都可以完美地工作。

@RequestMapping(value = "/emp2", produces = "application/json")
public List<Employee> getEmp2()
{
    HttpHeaders headers = new HttpHeaders();
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    HttpEntity<String> entity = new HttpEntity<String>(headers);
    ResponseEntity<List<Employee>> response = restTemplate.exchange(
            "http://hello-server/rest/employees", HttpMethod.GET,entity, 
    new ParameterizedTypeReference<List<Employee>>() {});
    return response.getBody();
}

(OR)

@RequestMapping(value = "/emp3", produces = "application/json")
public List<Employee> getEmp3()
{
    Employee[] empArray = restTemplate.getForObject("http://hello-server/rest/employees", Employee[].class);
    List<Employee> emp= Arrays.asList(empArray);
    return emp;
}

(OR)

    @RequestMapping(value = "/emp4", produces = "application/json")
public Employee[] getEmp4()
{
    ResponseEntity<Employee[]> responseEntity = restTemplate.getForEntity("http://hello-server/rest/employees", Employee[].class);
    Employee[] empList = responseEntity.getBody();
    //MediaType contentType = responseEntity.getHeaders().getContentType();
    //HttpStatus statusCode = responseEntity.getStatusCode();
    return  empList;
}

Employee.class

public class Employee {

private Integer id;
private String name;
private String Designation;
private String company;

//getter setters and toString()

}

3

我在这里面临的主要问题是建立所需的对象结构,以匹配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;
    }
}

我希望这能帮助到某些人!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接