美文网首页
Spring-RestTemplate常用方式汇总

Spring-RestTemplate常用方式汇总

作者: 艺超51iwowo | 来源:发表于2021-05-15 17:57 被阅读0次

当使用SpringBoot时,如果需要调用第三方Rest API,通常会使用RestTemplate。有时候偶尔搞不清楚参数要如何传递,明明参数已经赋值,对方接收到的确是空值。本文对经常使用的方式,做一下汇总。

准备工作
请求对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
  private Long id;

  private String name;
}

第三方请求

@RestController
public class PersonController {
        
    // 存储一下id和person的关系
    private static Map<Long, Person> persons = new HashMap<>();
        // 生成person的id
    private static final LongAdder ID_ADDER = new LongAdder();
    static {
        ID_ADDER.add(1L);
        Person person = new Person();
        person.setId(ID_ADDER.longValue());
        person.setName("1-person");
        persons.put(person.getId(), person);
    }
  ...省略其他
}

对于第三方接口仅简单实现,忽略一些诸如参数校验的细节问题。

RestTemplate访问get接口
请求参数在路径中

第三方接口,根据id查询Person

@GetMapping("/getPerson/{id}")
public Person getPersonPathVariable(@PathVariable(name = "id") Long id) {
  return persons.getOrDefault(id, new Person());
}

请求示例

// 请求Get
URI uri = UriComponentsBuilder.fromUriString(String.format(URL_FORMAT, "/getPerson/{id}")).build(1L);
ResponseEntity<Person> forEntity = REST_TEMPLATE.getForEntity(uri, Person.class);
log.info("getForEntity result:{}", forEntity);

Person forObject = REST_TEMPLATE.getForObject(uri, Person.class);
log.info("getForObject result:{}", forObject);

ResponseEntity除了正常返回结果,还包含HTTP相关了一些信息,具体可以看下面的日志。

16:10:48.391 [main] INFO com.yichao.myblogs.resttemplate.RestTemplateTest - getForEntity result:<200,Person(id=1, name=1-person),[Content-Type:"application/json", Transfer-Encoding:"chunked", Date:"Sat, 15 May 2021 08:10:48 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
通用的请求参数传递,即?name=xxx&id=xxx

第三方接口,根据id查询Person

@GetMapping("/getPerson")
public Person getPersonWithParams(HttpServletRequest httpServletRequest) {
  String idStr = httpServletRequest.getParameter("id");
  return persons.getOrDefault(Long.valueOf(idStr), new Person());
}

请求示例

// 请求Get
URI uri = UriComponentsBuilder.fromUriString(String.format(URL_FORMAT, "/getPerson/{id}")).build(1L);

uri = UriComponentsBuilder.fromUriString(String.format(URL_FORMAT, "/getPerson?id={id}")).build(1L);
ResponseEntity<Person> forEntity = REST_TEMPLATE.getForEntity(uri, Person.class);
log.info("getForEntity result:{}", forEntity);

Person forObject = REST_TEMPLATE.getForObject(uri, Person.class);
log.info("getForObject result:{}", forObject);
RestTemplate访问post接口

下面以API参数的几种不同形式进行区分。

参数使用@RequestBody

第三方接口,将传入的Person存储,并返回添加了主键的Person对象。

@PostMapping("/add/requestBody")
public Person postRequestBody(@RequestBody Person person) {
  ID_ADDER.add(1L);
  Long id = ID_ADDER.longValue();
  person.setId(id);
  persons.put(person.getId(), person);
  return person;
}

请求示例

String url = String.format(URL_FORMAT, "/add/requestBody");
Person person;
ResponseEntity<Person> responseEntity;

// 生成一个仅包含name的对象,由第三方接口负责生成id,并返回
Person mockPerson = mockPerson();

person = REST_TEMPLATE.postForObject(url, mockPerson, Person.class);
log.info("requestBody postForObject result:{}", person);

responseEntity = REST_TEMPLATE.postForEntity(url, mockPerson, Person.class);
log.info("requestBody postForEntity result:{}", responseEntity);
直接使用对象

第三方接口

@PostMapping("/add/form")
public Person postForm(Person person) {
  ID_ADDER.add(1L);
  Long id = ID_ADDER.longValue();
  person.setId(id);
  persons.put(person.getId(), person);
  return person;
}

请求示例

// form 请求格式
String url = String.format(URL_FORMAT, "/add/form");
HttpHeaders headers = new HttpHeaders();

Person mockPerson = mockPerson();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
// 将请求对象转为map,并添加到multiValueMap中
@SuppressWarnings("unchecked")
Map<String, Object> params = JSON.parseObject(JSON.toJSONString(mockPerson), Map.class);
params.forEach(map::add);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, headers);
Person person = REST_TEMPLATE.postForObject(url, httpEntity, Person.class);
log.info("form postForObject result:{}", person);

ResponseEntity<Person> responseEntity = REST_TEMPLATE.postForEntity(url, httpEntity, Person.class);
log.info("form postForEntity result{}", responseEntity);
使用HttpServletRequest

第三方接口

@PostMapping("/add/requestParam")
public Person postRequestParam(HttpServletRequest httpServletRequest) {
    ID_ADDER.add(1L);
    String name = httpServletRequest.getParameter("name");
    Long id = ID_ADDER.longValue();
    Person person = new Person();
    person.setId(id);
    person.setName(name);
    persons.put(person.getId(), person);
    return person;
}

请求示例

该方法同form的请求方式一致

String url = String.format(URL_FORMAT, "/add/requestParam");
HttpHeaders headers = new HttpHeaders();

Person mockPerson = mockPerson();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
// 将请求对象转为map,并添加到multiValueMap中
@SuppressWarnings("unchecked")
Map<String, Object> params = JSON.parseObject(JSON.toJSONString(mockPerson), Map.class);
params.forEach(map::add);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, headers);
Person person = REST_TEMPLATE.postForObject(url, httpEntity, Person.class);
log.info("requestParam postForObject result:{}", person);

ResponseEntity<Person> responseEntity = REST_TEMPLATE.postForEntity(url, httpEntity, Person.class);
log.info("requestParam postForEntity result{}", responseEntity);
高级用法
接口返回泛型

第三方接口,返回Person列表

@GetMapping("/listAll")
public List<Person> list() {
  return new ArrayList<>(persons.values());
}

请求示例

String url = String.format(URL_FORMAT, "listAll");
// 指定参数类型,这个里面会实际存储返回的类型
ParameterizedTypeReference<List<Person>> parameterizedTypeReference = new ParameterizedTypeReference<List<Person>>() {
};
ResponseEntity<List<Person>> exchange = REST_TEMPLATE.exchange(url, HttpMethod.GET, null, parameterizedTypeReference);
log.info("testGeneric result:{}", exchange);
List<Person> personList = exchange.getBody();
log.info("person List:{}", personList);
定制化RestTemplate

这里主要是对RestTemplate的一些属性进行设置,比如设置RestTemplate使用的http连接池信息,示例代码如下

private static HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
  try {
    HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
    // 开始设置连接池
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
      new PoolingHttpClientConnectionManager();
    // 最大连接数
    poolingHttpClientConnectionManager.setMaxTotal(100);
    // 同路由并发数
    poolingHttpClientConnectionManager.setDefaultMaxPerRoute(10);
    httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
    // 不进行重试
    httpClientBuilder.setRetryHandler(new HttpRequestRetryHandler() {
      @Override
      public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
        if (exception instanceof org.apache.http.NoHttpResponseException) {
          // 此类情况需要进行重试
          log.warn("No response from server on " + executionCount + " call");
          return true;
        }
        return false;
      }
    });

    HttpClient httpClient = httpClientBuilder.build();
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
      // httpClient连接配置
      new HttpComponentsClientHttpRequestFactory(httpClient);
    // 连接超时
    clientHttpRequestFactory.setConnectTimeout(5000);
    // 数据读取超时时间
    clientHttpRequestFactory.setReadTimeout(30000);
    // 连接不够用的等待时间
    clientHttpRequestFactory.setConnectionRequestTimeout(5000);
    return clientHttpRequestFactory;
  } catch (Exception e) {
    log.error("初始化HTTP连接池出错", e);
  }
  return null;
}

设置RestTemplate

new RestTemplateBuilder().requestFactory(() -> clientHttpRequestFactory()).build();
最后

RestTemplate的功能非常强大,本文主要介绍了一些常用的功能,以及之前踩过的坑,希望可以帮助到大家。

相关文章

网友评论

      本文标题:Spring-RestTemplate常用方式汇总

      本文链接:https://www.haomeiwen.com/subject/rwkkjltx.html