Spring boot 将RestTemplate响应映射到java对象

Spring boot 将RestTemplate响应映射到java对象,spring-boot,resttemplate,jackson2,Spring Boot,Resttemplate,Jackson2,我正在使用restemplate从远程rest服务获取数据,我的代码如下 ResponseEntity<List<MyObject >> responseEntity = restTemplate.exchange(request, responseType); 但我不喜欢这种方法。是否有更好的解决方案。首先,您可以为整个API编写一个包装器。用@Component注释它,您可以在任何地方使用它。看一下使用swagger codegen为resttemplate客户端生

我正在使用
restemplate
从远程rest服务获取数据,我的代码如下

ResponseEntity<List<MyObject >> responseEntity = restTemplate.exchange(request, responseType);

但我不喜欢这种方法。是否有更好的解决方案。

首先,您可以为整个API编写一个包装器。用@Component注释它,您可以在任何地方使用它。看一下使用swagger codegen为resttemplate客户端生成的代码的显示

正如您所说,您尝试实现自定义ResponseErrorHandler但未成功,我假设API返回响应正文
“未找到记录”
,而状态代码为
200

因此,您可以创建一个自定义的
AbstractHttpMessageConverter
,如我在第二个答案中所述。因为您使用的是springs resttemplate,它将objectmapper与jackson一起使用,所以我们不必使用这个非常通用的超类来创建我们自己的事件。我们可以使用和扩展更合适的
AbstractJackson2HttpMessageConverter
类。 特定用例的实现可以如下所示:

import com.fasterxml.jackson.databind.JavaType;
导入com.fasterxml.jackson.databind.ObjectMapper;
导入org.springframework.http.HttpInputMessage;
导入org.springframework.http.MediaType;
导入org.springframework.http.converter.httpmessagenoteradableexception;
导入org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
导入java.io.BufferedReader;
导入java.io.IOException;
导入java.io.InputStreamReader;
导入java.lang.reflect.Type;
导入java.util.Collection;
导入java.util.Collections;
导入java.util.Map;
导入java.util.stream.collector;
公共类WeirdAPIJackson2HttpMessageConverter扩展了AbstractJackson2HttpMessageConverter{
公共静态最终字符串NO\u RECORD\u FOUND=“NO RECORD FOUND”;
公共古怪的Jackson2HttpMessageConverter(){
//如果要传递已存在的ObjectMapper,请创建另一个构造函数
//目前,此HttpMessageConverter适用于每种媒体类型,这取决于应用程序
super(新的ObjectMapper(),MediaType.ALL);
}
@凌驾
公共对象读取(类型类型,类contextClass,HttpInputMessage inputMessage)引发IOException,HttpMessageNodeReadableException{
try(BufferedReader br=new BufferedReader(new InputStreamReader(inputMessage.getBody(),默认字符集))){
String responseBodyStr=br.lines().collect(collector.joining(System.lineSeparator());
if(找不到记录等于(responseBodyStr)){
JavaType JavaType=super.getJavaType(类型,contextClass);
if(Collection.class.isAssignableFrom(javaType.getRawClass())){
返回集合。emptyList();
}else if(Map.class.isAssignableFrom(javaType.getRawClass())){
return Collections.emptyMap();
}
返回null;
}
}
返回super.read(类型、contextClass、inputMessage);
}
}
自定义HttpMessageConverter正在检查特定“未找到记录”的响应正文。如果是这种情况,我们将根据泛型返回类型尝试返回默认值。如果返回类型是集合的子类型,则Atm返回空列表,set为空集,其他所有类类型为null

此外,我还使用MockRestServiceServer创建了一个RestClientTest,以演示如何在上述API包装器组件中使用RestTemplate,以及如何将其设置为使用我们的自定义AbstractJackson2HttpMessageConverter

import org.junit.Test;
导入org.junit.runner.RunWith;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
导入org.springframework.boot.web.client.RestTemplateBuilder;
导入org.springframework.core.ParameterizedTypeReference;
导入org.springframework.http.HttpMethod;
导入org.springframework.http.HttpStatus;
导入org.springframework.http.ResponseEntity;
导入org.springframework.test.context.ContextConfiguration;
导入org.springframework.test.context.junit4.SpringRunner;
导入org.springframework.test.web.client.ExpectedCount;
导入org.springframework.test.web.client.MockRestServiceServer;
导入org.springframework.web.client.rest模板;
导入java.util.List;
导入java.util.Optional;
导入静态org.junit.Assert.*;
导入静态org.springframework.test.web.client.match.MockRestRequestMatchers.method;
导入静态org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
导入静态org.springframework.test.web.client.response.mockresponsesecretors.withStatus;
@RunWith(SpringRunner.class)
@ContextConfiguration(类={RestTemplateResponseErrorHandlerIntegrationTest.MyObject.class})
@RestClientTest
公共类RestTemplateResponseErrorHandlerIntegrationTest{
静态类MyObject{
//这只是指你在回答中提到的MyObject类
}
私有最终静态字符串请求_API_URL=“/API/myobjects/”;
私有最终静态字符串请求\u API\u URL\u SINGLE=“/API/myobjects/1”;
@自动连线
私有MockRestServiceServer;
@自动连线
私人RestTemplateBuilder;
@试验
公共无效测试\u自定义\u转换器\u关于\u怪异\u api\u响应\u列表(){
assertNotNull(this.builder);
assertNotNull(this.server);
RestTemplate RestTemplate=this.builder
.MessageConverter(新的WeirdAPIJackson2HttpMessageConverter())
.build();
this.server.expect(ExpectedCount.once(),requestTo(REQUEST\u API\u URL))
.andExpect(方法(HttpMethod.GET))
.andRespond(带有status(HttpStatus.OK).body(古怪的Jackson2httpMessageConverter.未找到记录));
this.server.expect(ExpectedCount.o
ResponseEntity<String> responseEntity = restTemplate.exchange(request, responseType);
String jsonInput= response.getBody();
List<MyObject> myObjects = objectMapper.readValue(jsonInput, new TypeReference<List<MyObject>>(){});
List<Map> list = null;
List<MyObject> listObjects = new ArrayList<MyObject>();
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);

ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);

if (response != null && response.getStatusCode().value() == 200) {
    list = (List<Map>) response.getBody().get("items"); // this depends on the response
    for (Map item : list) { // we iterate for each one of the items of the list transforming it
        MyObject myObject = transform(item);
        listObjects.add(myObject);
    }
}