目录
RestTemplate 一种调用RESTful接口的方式,它简化了与HTTP服务器的通信,并实施了RESTful原则。(拦截器相关有时间整理)
# 使用前说明:
- 在新版本springboot中直接使用@Autowired注解注入RestTemplate
- 老版本springboot以及spring项目需要手动添加配置,配置如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class WebConfiguration {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
在需要的类中加入@Autowired
RestTemplate 注入成功后就可以调用api来访问三方接口了。
- 在RestTemplate类中,不管是get还是post请求都是RestTemplate自己封装的方法,里面调用的都是函数
execute();
exectue方法则是调用的包级别的<T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor)
;如果RestTemplate提供的get和post等相关方法不满足需求,可以调用execute();
- 不管是get、post相关方法还是exectue()方法如果请求失败都会直接抛出
throws RestClientException
异常,导致无法获取到异常时的响应内容。如果想获取响应内容需要在配置里重写方法,具体配置见 获取调用失败的返回体 - RestTemplate默认依赖于标准JDK建立HTTP连接。可以通过
setRequestFactory
属性切换到使用其他http源,如Apache HttpComponents, Netty, and OkHttp
- RestTemplate中每个HTTP方法都有三个变体,分别是 接受URI模板字符串、URI变量(数组或映射)和 URI 类。通常3种均可,但是如果使用前两种时url参数或模板已经被编码,那么调用后将发生双重编码,建议直接传入 URI 类。
1. GET请求相关方法
(1)getForObject
<T> T getForObject()
get方法请求,返回泛型T对应响应体中数据。以下是其三个重载方法。
<T> T getForObject(String url, Class<T> responseType, Object... urlVariables)
参数依次为:字符串类型url,T类型响应类型,Object类型url参数
<T> T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables)
字符串类型url,T类型响应类型,Map类型url参数
<T> T getForObject(URI url, Class<T> responseType)
URI 以及响应类型
调用示例:(无参调用以及两种url参数调用,URI不作演示,其余方法都相同)
String url = "http://localhost:8080/testGet";
JSONObject responseObj = restTemplate.getForObject(url, JSONObject.class);
String url1 = "http://localhost:8080/testGet1/{1}/{2}";
JSONObject responseObj = restTemplate.getForObject(url1, JSONObject.class, "11", "22");
String url2 = "http://localhost:8080/testGet2?a={param1}&b={param2}";
Map<String, String> uriVariables = new HashMap<>();
uriVariables.put("param1", "aaaa");
uriVariables.put("param2", "bbbbb");
JSONObject responseObj = restTemplate.getForObject(url1, JSONObject.class, uriVariables );
(2)getForEntity
<T> ResponseEntity<T> getForEntity
get请求,返回ResponseEntity类型除响应体外的 头信息、状态码等。方法参数同上。
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables)
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables)
<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType)
调用示例:
String url = "http://localhost:8080/testGet";
ResponseEntity<JSONObject> responseEntity = restTemplate.getForEntity(url, JSONObject.class);
JSONObject responseBody = responseEntity .getBody();// 获取body
HttpStatus statusCode = responseEntity .getStatusCode(); // 状态码
HttpHeaders headers = responseEntity .getHeaders(); // 获取header
2. POST请求相关
设置请求头和请求体:HttpEntity
post系列请求比get请求多了一个Object类型的request参数,比如<T> T postForObject(URI url, Object request, Class<T> responseType)
。这个参数一般用HttpEntity<T>
来传参。感兴趣的小伙伴可以去源码里看看这个类的几个构造函数。
HttpEntity(T body, MultiValueMap<String, String> headers):
写几个例子:
// 没有headers和body可以直接设置null或者 new HttpEntity();
HttpEntity request = new HttpEntity();
// 只有headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 也可用MultiValueMap<String, String> headers来创建headers
HttpEntity request = new HttpEntity(headers);
// 只有body
String json = "{\"auth\": \"1111\"}";
HttpEntity<JSONObject> requestEntity = new HttpEntity<JSONObject>(JSONObject.parseObject(json ));
//headers和body
HttpEntity<JSONObject> requestEntity = new HttpEntity<JSONObject>(JSONObject.parseObject(requestBody),headers);
组合好请求体就可以调用下面的方法来调接口了。
(1)postForLocation
URI postForLocation()
返回URI,多数场景为返回post添加的数据的URI
三种参数方法:
URI postForLocation(String url, Object request, Object... urlVariables)
URI postForLocation(String url, Object request, Map<String, ?> urlVariables)
URI postForLocation(URI url, Object request)
(2)postForObject
<T> T postForObject
返回响应体
同样,三种参数
<T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
<T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
<T> T postForObject(URI url, Object request, Class<T> responseType)
(3)postForEntity
<T> ResponseEntity<T> postForEntity
返回ResponseEntity
三种参数
<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
<T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType)
post系列这里放一个完整的示例:
String url = "http://localhost:8080/testPost";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String json = "{\"auth\": \"1111\"}";
HttpEntity<JSONObject> requestEntity = new HttpEntity<JSONObject>(JSONObject.parseObject(requestBody),headers);
ResponseEntity<JSONObject> responseObj = restTemplate.postForEntity(url,requestEntity,JSONObject.class);
JSONObject responseBody = responseObj.getBody();
3. put、delete
只列方法,调用参数和以上相同,没有返回值。
void put(String url, Object request, Object... urlVariables)
void put(String url, Object request, Map<String, ?> urlVariables)
void put(URI url, Object request)
void delete(String url, Object... urlVariables)
void delete(String url, Map<String, ?> urlVariables)
void delete(URI url)
4. options 预检请求
返回的是headers.getAllow();
三种调用方法:
Set<HttpMethod> optionsForAllow(String url, Object... urlVariables)
Set<HttpMethod> optionsForAllow(String url, Map<String, ?> urlVariables)
Set<HttpMethod> optionsForAllow(URI url)
5. exchange()万能调用
相对于其他方法,我更喜欢用这个方法来进行一些封装,比较灵活,支持 GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE
。返回类型固定为ResponseEntity<T>
具体方法如下:(前两个方法主要是参数Class<T> responseType
和ParameterizedTypeReference<T> responseType
的不同,每个方法各自有三种url的传递方式,这里只列一种;后两个方法是把请求url和请求体等信息统一封装到RequestEntity
类中,看需求和习惯选择调用)。
<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Object... uriVariables)
<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType)
<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
调用示例:
String url = "http://localhost:8080/testPost";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String json = "{\"auth\": \"1111\"}";
HttpEntity<JSONObject> requestEntity = new HttpEntity<JSONObject>(JSONObject.parseObject(requestBody),headers);
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity,JSONObject.class);
6. execute()万能调用
和exchange方法一样,只不过这个方法是所有封装方法的底层调用,返回的是泛型T的响应体对象。
<T> T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor, Object... urlVariables)
也有三种url参数调用,不列了。
调用示例,看源码:
@Override
public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, method, requestCallback, responseExtractor);
}
7. 获取调用失败的返回体
restTemplate默认调用失败时抛出异常 RestClientException
,因此正常是无法获取到调用失败时的返回信息,会直接抛出异常。
比如postman测试调用失败时会返回 :
{
"error": {
"message": "Tenant [6d16e50f0cf142b398cbb643cb78be51] token is expired. ",
"code": "Common.0013"
}
}
想获取内容需要设置一下 restTemplate类的errorHandler。
具体操作:之前注入bean时新增如下:
import java.io.IOException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
@Configuration
public class WebConfiguration {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new getErrorBodyHandler());
return restTemplate;
}
public static class getErrorBodyHandler implements ResponseErrorHandler{
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
}
}
}
调用示例:
ResponseEntity<Object> responeEntity = restTemplate.postForEntity(url, requestEntity, Object.class);
HttpStatus httpStatus = responeEntity.getStatusCode();
if (HttpStatus.OK.equals(httpStatus) || HttpStatus.CREATED.equals(httpStatus)) {
HttpHeaders responseHeaders = responeEntity.getHeaders();
String token = responseHeaders.get("X-Subject-Token").get(0);
if (!StringUtils.isBlank(token)) {
tokenString = token;
return tokenString;
}
} else {
// 调用失败
LinkedHashMap<String, String> errorHashMap = (LinkedHashMap<String, String>)requestEntity.getBody().get("error");
logger.error(errorHashMap.get("message")+","+errorHashMap.get("code"));
}