當(dāng)使用SpringBoot時(shí)旱函,如果需要調(diào)用第三方Rest API准给,通常會(huì)使用RestTemplate泄朴。有時(shí)候偶爾搞不清楚參數(shù)要如何傳遞,明明參數(shù)已經(jīng)賦值露氮,對(duì)方接收到的確是空值祖灰。本文對(duì)經(jīng)常使用的方式,做一下匯總畔规。
準(zhǔn)備工作
請(qǐng)求對(duì)象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private Long id;
private String name;
}
第三方請(qǐng)求
@RestController
public class PersonController {
// 存儲(chǔ)一下id和person的關(guān)系
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);
}
...省略其他
}
對(duì)于第三方接口僅簡(jiǎn)單實(shí)現(xiàn)局扶,忽略一些諸如參數(shù)校驗(yàn)的細(xì)節(jié)問(wèn)題。
RestTemplate訪問(wèn)get接口
請(qǐng)求參數(shù)在路徑中
第三方接口叁扫,根據(jù)id查詢Person
@GetMapping("/getPerson/{id}")
public Person getPersonPathVariable(@PathVariable(name = "id") Long id) {
return persons.getOrDefault(id, new Person());
}
請(qǐng)求示例
// 請(qǐng)求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除了正常返回結(jié)果三妈,還包含HTTP相關(guān)了一些信息,具體可以看下面的日志莫绣。
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"]>
通用的請(qǐng)求參數(shù)傳遞畴蒲,即?name=xxx&id=xxx
第三方接口,根據(jù)id查詢Person
@GetMapping("/getPerson")
public Person getPersonWithParams(HttpServletRequest httpServletRequest) {
String idStr = httpServletRequest.getParameter("id");
return persons.getOrDefault(Long.valueOf(idStr), new Person());
}
請(qǐng)求示例
// 請(qǐng)求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訪問(wèn)post接口
下面以API參數(shù)的幾種不同形式進(jìn)行區(qū)分对室。
參數(shù)使用@RequestBody
第三方接口模燥,將傳入的Person存儲(chǔ)咖祭,并返回添加了主鍵的Person對(duì)象。
@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;
}
請(qǐng)求示例
String url = String.format(URL_FORMAT, "/add/requestBody");
Person person;
ResponseEntity<Person> responseEntity;
// 生成一個(gè)僅包含name的對(duì)象蔫骂,由第三方接口負(fù)責(zé)生成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);
直接使用對(duì)象
第三方接口
@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;
}
請(qǐng)求示例
// form 請(qǐng)求格式
String url = String.format(URL_FORMAT, "/add/form");
HttpHeaders headers = new HttpHeaders();
Person mockPerson = mockPerson();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
// 將請(qǐng)求對(duì)象轉(zhuǎn)為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;
}
請(qǐng)求示例
該方法同form的請(qǐng)求方式一致
String url = String.format(URL_FORMAT, "/add/requestParam");
HttpHeaders headers = new HttpHeaders();
Person mockPerson = mockPerson();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
// 將請(qǐng)求對(duì)象轉(zhuǎn)為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);
高級(jí)用法
接口返回泛型
第三方接口硬鞍,返回Person列表
@GetMapping("/listAll")
public List<Person> list() {
return new ArrayList<>(persons.values());
}
請(qǐng)求示例
String url = String.format(URL_FORMAT, "listAll");
// 指定參數(shù)類型,這個(gè)里面會(huì)實(shí)際存儲(chǔ)返回的類型
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
這里主要是對(duì)RestTemplate的一些屬性進(jìn)行設(shè)置戴已,比如設(shè)置RestTemplate使用的http連接池信息固该,示例代碼如下
private static HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
try {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// 開(kāi)始設(shè)置連接池
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager();
// 最大連接數(shù)
poolingHttpClientConnectionManager.setMaxTotal(100);
// 同路由并發(fā)數(shù)
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(10);
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
// 不進(jìn)行重試
httpClientBuilder.setRetryHandler(new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if (exception instanceof org.apache.http.NoHttpResponseException) {
// 此類情況需要進(jìn)行重試
log.warn("No response from server on " + executionCount + " call");
return true;
}
return false;
}
});
HttpClient httpClient = httpClientBuilder.build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
// httpClient連接配置
new HttpComponentsClientHttpRequestFactory(httpClient);
// 連接超時(shí)
clientHttpRequestFactory.setConnectTimeout(5000);
// 數(shù)據(jù)讀取超時(shí)時(shí)間
clientHttpRequestFactory.setReadTimeout(30000);
// 連接不夠用的等待時(shí)間
clientHttpRequestFactory.setConnectionRequestTimeout(5000);
return clientHttpRequestFactory;
} catch (Exception e) {
log.error("初始化HTTP連接池出錯(cuò)", e);
}
return null;
}
設(shè)置RestTemplate
new RestTemplateBuilder().requestFactory(() -> clientHttpRequestFactory()).build();
最后
RestTemplate的功能非常強(qiáng)大,本文主要介紹了一些常用的功能糖儡,以及之前踩過(guò)的坑伐坏,希望可以幫助到大家。