什么是RestTemplate
RestTemplate是从Spring 3.0开始支执行Http请求的客户端工具,常见的Http客户端库有
Java JDK自带的HttpURLConnection
Apache HttpComponents
OkHttp
这些客户端库对,提供常见的REST请求模板,例如Get、Post、PUT和Delete请求,相对于直接使用底层Http客户端库,RestTemplate的操作更加方便、快捷在很大程度上提高开发效率。
HttpClient、OkHttp、RestTemplate对比:
HttpClient:代码复杂,还得操心资源回收等。代码很复杂,冗余代码多,不建议直接使用,一般是封装为 HttpUtils工具类使用。
RestTemplate: 是 Spring 提供的用于访问Rest服务的客户端, RestTemplate 提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
okhttp:OkHttp是一个高效的HTTP客户端,允许所有同一个主机地址的请求共享同一个socket连接;连接池减少请求延时;透明的GZIP压缩减少响应数据的大小;缓存响应内容,避免一些完全重复的请求
SpringBoot引入RestTemplate
从Spring3.0引入RestTemplate后它就作为spring-web的一部分,而spring-boot-starter-web保重包含了spring-web
因此只需要添加spring-boot-starter-web依赖即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
RestTemplate初始化
SpringBoot在AutoConfig的时候,自动注入了JDK自带的HttpURLConnection作为RestTemplate底层的Http客户端实现,也可以将底层的Http实现转换为OkHttp,Apache HttpComponents,并且需要初始化Bean。所以RestTemplate是支持多种方式发起请求的,查看该工程的实现类可知,支持包括HttpClient, OkHttp等方式。
@Configuration
public class MyRestTemplate {
/**
* 默认使用JDK 自带的HttpURLConnection作为底层实现
* @return
*/
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
底层Http客户端库切换
我们在网上对Http客户端的测评来看OkHttp的性能优于Apache HttpComponents和JDK自带的HttpURLConnection,那么我们如何将底层Http客户端库切换为我们需要使用的Http客户端库呢?
切换为OkHttp
添加依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.1</version>
</dependency>
初始化RestTemplate的Bean
@Bean
public RestTemplate restTemplateOkHttp(){
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
切换为Apache HttpComponents
添加依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
初始化RestTemplate的Bean
@Bean
public RestTemplate restTemplateHttpClient(){
return new RestTemplate(new HttpComponentsClientHttpRequestFactory());
}
RestTemplate的使用
基础原理
RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。RestTemplate 继承自 InterceptingHttpAccessor 并且实现了 RestOperations 接口,其中 RestOperations 接口定义了基本的 RESTful 操作,这些操作在 RestTemplate 中都得到了实现。
RestTemplate restTemplate = new RestTemplate();
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
RestTemplate提供了六种常用的HTTP方法实现远程服务调用,RestTemplate的方法名遵循一定的命名规范,第一部分表示用哪种HTTP方法调用(get,post),第二部分表示返回类型。
getForObject – 发送GET请求,将HTTP response转换成一个指定的object对象
postForEntity –发送POST请求,将给定的对象封装到HTTP请求体,返回类型是一个HttpEntity对象(包含响应数据和响应头)
每个HTTP方法对应的RestTemplate方法都有3种。其中2种的url参数为字符串,URI参数变量分别是Object数组和Map,第3种使用URI类型作为参数
exchange 和execute方法比上面列出的其它方法(如getForObject、postForEntity等)使用范围更广,允许调用者指定HTTP请求的方法(GET、POST、PUT等),并且可以支持像HTTP PATCH(部分更新)。
发送请求不携带数据
1、发起get请求请求
发送一个HTTP GET请求,返回的请求体将映射为一个对象
getForObject()
发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
getForEntity()
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> entity = restTemplate.getForEntity(uri, String.class);
// TODO 处理响应
2、发起Post请求方式
POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得到的。
postForEntity()
POST 数据到一个URL,返回根据响应体匹配形成的对象。
postForObject()
POST 数据到一个URL,返回新创建资源的URL
postForLocation()
RestTemplate restTemplate = new RestTemplate();
// headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
HttpEntity<Object> objectHttpEntity = new HttpEntity<>(headers);
// TODO 处理响应
ResponseEntity<String> entity = restTemplate.postForEntity(uri, request, String.class);
发送请求携带请求数据
方式一:在每次发送请求时,构建一个HttpEntity对象,传入请求参数与请求头
使用 RestTemplate 时可以通过 HttpEntity 设置请求头和请求体。HttpEntity 有4个构造方法:
既不设置请求体,也不设置请求头
只设置请求体
只设置请求头
同时设置请求体和请求头
@GetMapping("/test")
public Map<String, Object> getBlobMetadataList(){
// 构建你的请求头
HttpHeaders headers = new HttpHeaders();
headers.set("xxx","xxx");
headers.set("Content-Type", "application/json");
// 构建你的请求体参数
HashMap<String, String> map = new HashMap<>();
map.put("yourParma", "youValue");
// 组合请求头与请求体参数
HttpEntity<String> requestEntity = new HttpEntity<>(JSONObject.toJSONString(map), headers);
// path -> 请求地址,requestEntity -> 请求参数相关对象,HashMap.class -> 返回结果映射类型
return restTemplate.postForObject(path, requestEntity, HashMap.class);
}
方式二:通过配置RestTemplate,使通过RestTemplate调用的http请求都携带上请求头
对于一些共同的请求头,如果在每一次发送请求调用时都去重头构建一个HttpEntity请求头,在代码上重复不说,看着也不舒服,以下为配置统一的请求头,让每次请求都自动携带上请求头,一劳永逸!
同时设置请求头和请求体:
/**
* RestTemplate配置类
*/
@Slf4j
@Configuration
public class RestTemplateConfig {
/**
* 常用远程调用RestTemplate
* @return restTemplate
*/
@Bean("restTemplate")
public RestTemplate restTemplate(){
RestTemplate restTemplate = new RestTemplate();
// 设置通用的请求头
//HeaderRequestInterceptor myHeader = new HeaderRequestInterceptor("xxx","xxx");
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new HeaderRequestInterceptor("Content-type", "application/json;charset=UTF-8"));
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
/**
* 拦截器类,为restTemplatep后续调用请求时携带请求头
*/
public static class HeaderRequestInterceptor implements ClientHttpRequestInterceptor{
private final String header;
private final String value;
public HeaderRequestInterceptor(String header, String value){
this.header = header;
this.value = value;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().set(header, value);
return execution.execute(request, body);
}
}
}
为其他请求设置请求头、请求体
如果是其它HTTP方法调用要设置请求头,可以使用exchange()方法:
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyRequestHeader", "MyValue");
HttpEntity requestEntity = new HttpEntity(requestHeaders);
HttpEntity<String> response = template.exchange(
"http://example.com/hotels/{hotel}",
HttpMethod.GET,
requestEntity,
String.class,
"42"
);
String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();