Spring之RestTemplate常用API实践
Posted 一宿君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之RestTemplate常用API实践相关的知识,希望对你有一定的参考价值。
目录
- 1、RestTemplate简介
- 2、RestTemplate初始化配置
- 3、RestTemplate常用API实践
1、RestTemplate简介
在开发的过程中,很多时候我们需要从当前服务端(当前项目)向外进行网络请求(其他项目)获取数据或传送数据,传统情况下,我们一般会使用JDK
自带的HttpURLConnection
、Apache
提供的HttpClient
、OkHttp
等客户端请求工具,但是这几种方式使用起来比较繁琐,对于初学者来说不太友好,而Spring
为我们提供了一个快捷方便的Restful
模板类请求工具类RestTemplate
。
RestTemplate
是一个执行HTTP
请求的同步阻塞式请求工具类,它是在JDK HttpURLConnection
,Apache HttpComponents
,OkHttp
等客户端的基础上,封装了更高级别的API,使在单行中调用REST端点变得容易。RestTemplate
默认是依赖JDK HttpURLConnection
,可以根据实际需要通过构造函数中的setRequestFactory
方法设置底层依赖请求客户端。
public RestTemplate(ClientHttpRequestFactory requestFactory)
this();
this.setRequestFactory(requestFactory);//指定HTTP客户端
2、RestTemplate初始化配置
如果当前是非SpringBoot项目(非spring环境),我们需要导入Spring-web
依赖,即可引入RestTemplate
类:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
如果当前是SpringBoot项目(spring环境),我们只需要导入spring-boot-starter-web
依赖,即可引入RestTemplate
类:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
内置支持以下功能:
- JDK HttpURLConnection
- Apache HttpComponents
- OkHttp
RestTemplate包含以下几个部分:
HttpMessageConverter
对象转换器ClientHttpRequestFactory
默认是JDK
的HttpURLConnection
ResponseErrorHandler
异常处理器ClientHttpRequestInterceptor
请求拦截器
我们现在大多使用SpringBoot框架,为了后续方便使用,我们将RestTemplate
配置初始化为一个Bean
:
@Configuration
public class RestTemplateConfig
@Bean
@ConditionalOnMissingBean(RestTemplate.class)
public RestTemplate restTemplate()
RestTemplate restTemplate = new RestTemplate(getSimpleClientHttpRequestFactory());
return restTemplate;
/**
* 默认底层依赖JDK HttpURLConnection作为HTTP客户端
* @return
*/
public ClientHttpRequestFactory getSimpleClientHttpRequestFactory()
int timeout = 5000;
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(timeout);
factory.setConnectTimeout(timeout);
return factory;
在项目启动的时候会默认加载当前配置类中的@Bean
注解方法,将restTemplate()
方法注入Spring容器中,注意: @Bean
注解的方法名最好是restTemplate
首字母小写,后续我们在需要用到的地方直接@Autowire
自动装载即可使用。
@Autowired
private RestTemplate restTemplate;
通过管方指导文档描述:
The default constructor uses java.net.HttpURLConnection to perform requests. You can switch to a different HTTP library with an implementation of ClientHttpRequestFactory. There is built-in support for the following:
释义:默认构造函数使用java.net.HttpURLConnection执行请求。您可以切换到具有`ClientHttpRequestFactory`实现的不同HTTP库。
//直接new RestTemplate();底层依赖的也是JDK HttpURLConnection
如果我们想切换到Apache HttpComponents
客户端,可以使用以下方式:
首先导入Apache HttpClient
依赖:
<!-- Apache Httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
初始化:
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
但是通常情况下,我们切换客户端会预先做一些连接请求超时参数配置,如下:
@Configuration
public class RestTemplateConfig
/**
* 使用Apache HttpClient作为底层客户端
* @return
*/
@Bean
@ConditionalOnMissingBean(RestTemplate.class)
public RestTemplate restTemplate()
//RestTemplate restTemplate = new RestTemplate();
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
return restTemplate;
/**
* 使用Apache HttpClient作为底层客户端
* @return
*/
private ClientHttpRequestFactory getClientHttpRequestFactory()
int timeout = 5000;
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(timeout)
.setConnectTimeout(timeout)
.setSocketTimeout(timeout)
.build();
CloseableHttpClient client = HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.build();
return new HttpComponentsClientHttpRequestFactory(client);
切换为OkHttp客户端:
先导入依赖:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.7.2</version>
</dependency>
初始化:
RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
预先做一些连接请求超时参数配置,如下:
@Configuration
public class RestTemplateConfig
/**
* 使用OkHTTP作为底层客户端
* @return
*/
@Bean
@ConditionalOnMissingBean(RestTemplate.class)
public RestTemplate restTemplate()
//RestTemplate restTemplate = new RestTemplate();
//RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
RestTemplate restTemplate = new RestTemplate(getOkHttp3ClientHttpRequestFactory());
return restTemplate;
/**
* 使用OkHTTP作为底层客户端
* @return
*/
private OkHttp3ClientHttpRequestFactory getOkHttp3ClientHttpRequestFactory()
int timeout = 5000;
OkHttpClient okHttpClient = new OkHttpClient();
OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClient)
setConnectTimeout(timeout);
setReadTimeout(timeout);
setWriteTimeout(timeout);
;
return okHttp3ClientHttpRequestFactory;
具网上不完全统计,上述Http客户端的效率:
OkHttp > Apache HttpClient > JDK HttpURLConnection
所以下述我们以OkHttp作为底层客户端依赖。
扩展:
@ConditionalOnMissingBean(RestTemplate.class)
当注入多个相同类型的
Bean
时,会报异常,此注解就是保证当前类型Bean
只能有一个实例化对象。
@ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean
@ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean
@ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean
@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean
3、RestTemplate常用API实践
它公开了以下几组重载方法:
方法 | 描述 |
---|---|
getForObject | 通过GET检索一个表示。 |
getForEntity | 通过使用GET检索一个ResponseEntity (即状态、标题和主体)。 |
headForHeaders | 通过使用HEAD检索资源的所有标头。 |
postForLocation | 使用POST创建一个新资源,并从响应中返回Location 报头。 |
postForObject | 使用POST创建新资源,并从响应返回表示。 |
postForEntity | 使用POST创建新资源,并从响应返回表示。 |
put | 通过使用PUT创建或更新资源。 |
patchForObject | 使用PATCH更新资源,并从响应返回表示。注意,JDK HttpURLConnection 不支持PATCH ,但Apache HttpComponents 和其他组件支持。 |
delete | 使用DELETE删除指定URI处的资源。 |
optionsForAllow | 使用ALLOW为资源检索允许的HTTP方法。 |
exchange | 在需要时提供额外灵活性的前面方法的更一般化(且不那么自以为是)版本。它接受一个’RequestEntity (包括HTTP方法、URL、报头和主体作为输入),并返回一个ResponseEntity 。这些方法允许使用ParameterizedTypeReference 代替Class 来指定具有泛型的响应类型。 |
execute | 执行请求的最通用方法,通过回调接口完全控制请求准备和响应提取。 |
将上述方法大致归为三类:
常用的Rest API(GET、POST、PUT、DELETE):
getForObject
getForEntity
headForHeaders
postForLocation
postForObject
postForEntity
put
patchForObject
delete
optionsForAllow
接收一个 RequestEntity
参数,自定义设置HTTP method
,URL
,headers
和body
,返回 ResponseEntity:
exchange
通过 callback 接口,可以对请求和返回做更加全面的自定义控制:
execute
创建一个响应实体类ResponseBean
:
@Data
@ToString
public class ResponseBean<T>
/**
* 状态码 200 成功 其他失败
*/
private String code;
/**
* 响应数据
*/
private T data;
/**
* 异常信息
*/
private String message;
创建一个请求实体类RequestBean
:
@Data
public class RequestBean
/**
* 用户id
*/
private String userCode;
/**
*
*/
private String userName;
3.1、GET类型方法
通过RestTemplate
发送HTTP GET
协议请求,经常会用到以下两个方法:
getForObject()
:返回值是HTTP
协议的响应体内容getForEntity()
:返回的是ResponseEntity
,ResponseEntity
是对HTTP
响应的封装,除了包含响应体,还包含HTTP
状态码、contentType、contentLength、Header
等信息
getForObject()
重载方法:
@Nullable
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException
@Nullable
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException
@Nullable
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException
getForEntity()
重载方法:
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException
3.1.1、GET无参请求方法之getForObject()
创建一个无参get请求接口:
@RestController
@RequestMapping("/rest")
public class RestTemplateController
@Autowired
private RestTemplate restTemplate;
@GetMapping("/no/param/test/get")
public ResponseBean<String> testGet1()
ResponseBean<String> responseBean = new ResponseBean<String>();
responseBean.setCode("200");
responseBean.setData("无参get请求!");
responseBean.setMessage(null);
return responseBean;
单元测试无参get请求:
@SpringBootTest
@RunWith(SpringRunner.class)
public class RestTemplateTest
@Autowired
private RestTemplate restTemplate;
@Test
public void testGet1()
String url = "http://localhost:6625/rest/no/param/test/get";
ResponseBean response = restTemplate.getForObject(url, ResponseBean.class);
System.out.println(response);
打印结果:
"code":"200","data":"å“应æˆåŠŸäº†ï¼","message":null
发现出现了乱码,原因在于RestTemplate中对字符串默认使用的转换器是StringHttpMessageConverter
,而StringHttpMessageConverter
默认的字符集编码是ISO_8859_1
:
public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String>
public static final Charset DEFAULT_CHARSET;
public StringHttpMessageConverter()
this(DEFAULT_CHARSET);
static
//默认字符集
DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
ISO_8859_1
编码格下,中文是乱码的。因此我们需要将编码格式设置为UTF-8
的格式才能支持中文:
@Configuration
public class RestTemplateConfig
@Bean
@ConditionalOnMissingBean(RestTemplate.class)
public RestTemplate restTemplate()
RestTemplate restTemplate = new RestTemplate(getOkHttp3ClientHttpRequestFactory());
//设置RestTemplate的字符集为UTF-8
setRestTemplateEncode(restTemplate);
return restTemplate;
/**
* 使用OkHTTP作为底层客户端
* @return
*/
private OkHttp3ClientHttpRequestFactory getOkHttp3ClientHttpRequestFactory()
int timeout = 5000;
OkHttpClient okHttpClient = new OkHttpClient();
OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClient)
setConnectTimeout(timeout);
setReadTimeout(timeout);
setWriteTimeout(timeout);
;
return okHttp3ClientHttpRequestFactory;
/**
* 指定设置RestTemplate的字符转换器编码为UTF_8
* @param restTemplate
*/
public static void setRestTemplateEncode(RestTemplate restTemplate)
if (ObjectUtils.isEmpty(restTemplate) || ObjectUtils.isEmpty(restTemplate.getMessageConverters()))
return;
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (int i = 0; i < messageConverters.size(); i++)
HttpMessageConverter<?> httpMessageConverter = messageConverters.get(i);
if (StringHttpMessageConverter.class.equals(httpMessageConverter.getClass()))
messageConverters.set(i,new StringHttpMessageConverter(StandardCharsets.UTF_8));
再次重启,打印结果:
ResponseBean(code=200, data=无参get请求!, message=null)
问题解决!
3.1.2、GET占位符传参请求方法之getForObject()
创建一个占位符传参get请求接口:
@RestController
@RequestMapping("/rest")
public class RestTemplateController
@Autowired
private RestTemplate restTemplate;
@GetMapping("/path/param/test/get/code/data")
public ResponseBean<String> testGet2(@PathVariable("code") String code,@PathVariable("data") String data)
ResponseBean<String> responseBean = new ResponseBean<String>();
responseBean.setCode(code);
responseBean.setData(data);
responseBean.setMessage(null);
return responseBean;
单元测试占位符传参get请求:
@SpringBootTest
@RunWith(SpringRunner.class)
public class RestTemplateTest
@Autowired
private RestTemplate restTemplate;
@Test
public void testGet2()
String url = "http://localhost:6625/rest/path/param/test/get/code/data";
ResponseBean response = restTemplate.getForObject(url, ResponseBean.class,"200","占位符传参get请求&以上是关于Spring之RestTemplate常用API实践的主要内容,如果未能解决你的问题,请参考以下文章