初识RestTemplate
- RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
- RestTemplate默认依赖jdk的HTTP连接工具。当然你也可以通过setRequestFactory属性切换到不同的HTTP源,比如Apache、HttpComponents、Netty和OkHttp。
- RestTemplate能大幅简化了提交表单数据的难度,并且附带了自动转换JSON数据的功能(注意这个功能非常好用),
一、如果你只是想使用这个来发送http请求,而不研究他的原理,看我下文写的Demo就好了
1、配置POM(注意不要重复引入)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath />
</parent>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
2、初始化Bean
@Configuration
public class RestTemplateConfig {
@Bean
@Primary
public RestTemplate restTemplate(){
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(300000); //连接请求超时时间
httpRequestFactory.setConnectTimeout(300000); //连接超时时间
httpRequestFactory.setReadTimeout(300000); //读取超时时间
return new RestTemplate(httpRequestFactory);
}
}
上面使用HttpComponentsClientHttpRequestFactory来创建RestTemplate,如果需要使用Okhttp创建就替换成OkHttp3ClientHttpRequest
3、程序中注入
@Autowired
private RestTemplate restTemplate;
4、发送GET请求
//1、无参数
XXDTO result1 = restTemplate.getForObject("http://localhost:8080/admin/getTest", XXDTO.class);
//2、有参
XXDTO result2 = restTemplate.getForObject("http://localhost:8080/admin/getTestEn/?parame1={parame1}¶me2={parame2}", XXDTO.class, 1, 5);
//3、有参
HashMap<String,String> map = new HashMap<String,String>();
map.put("parame1","1");
map.put("parame2","2");
XXDTO result3 = restTemplate.getForObject("http://localhost:8080/admin/getTestEn/?parame1={parame1}¶me2={parame2}", XXDTO.class, map);
//4、有参
HashMap<String,String> map = new HashMap<String,String>();
map.put("parame1","1");
map.put("parame2","2");
ResponseEntity<XXDTO> entity = restTemplate.getForEntity("http://localhost:8080/admin/getTestEn/?parame1={parame1}¶me2={parame2}" , XXDTO.class,map);
XXDTO result4 = entity.getBody();
5、POST(from-data) 请求
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
List<String> list = new ArrayList<>();
list.add("1");//注意只能add一个,add多个不会报错,但是参数会变成parame1=[1,2,3],为什么要塞List,下面我会介绍
List<String> list2 = new ArrayList<>();
list2.add("1");
map.put("parame1", list);
map.put("parame2", list2);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);//设置表单方式
HttpEntity<MultiValueMap<String, String>> mapHttpEntity = new HttpEntity<>(map, headers);
ResponseEntity<XXDTO> xxdtoResponseEntity = restTemplate.postForEntity("http://localhost:8080/admin/postTestEn", mapHttpEntity, XXDTO.class);
XXDTO body = xxdtoResponseEntity.getBody();
6、POST(APPLICATION-JSON)
Map<String,Object> map = new HashMap<String,Object>();
map.put("id", 1);
map.put("bizType", 2);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map> request2 = new HttpEntity<>(map, headers);//注意这个是HashMap类型
ResponseEntity<XXDTO> xxdtoResponseEntity = restTemplate.postForEntity("http://localhost:8080/admin/postJsonTestEn", request2, XXDTO.class);
XXDTO body = xxdtoResponseEntity.getBody();
如果你只是想知道怎么使用,而不想了解原理到这里已经OK了
二、深入
先介绍几个重要的类
1、RestTemplate
属性
//里面会存url且处理url,因为url里面可能会有变量,需要处理。这个类还是蛮强大的。
1、private UriTemplateHandler uriTemplateHandler;
//请求参数和resp回来的数据序列化和反序列化。对messageConverter的选择是基于请求header中的Content-Type。在构造时就会塞数据
2、private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
//这个属性是来自于RestTemplate的父类。在发出请求前个用户一个可以切入操作的地方。类似于请求发出前的拦截器。下面会使用一个请求前往Cookies里面塞入token案例来介绍这个。
3、private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
内部类
//内部类,RequestCallback是用来处理请求头和body的,而AcceptHeaderRequestCallback只处理请求头,用于Get请求处理。
1、private class AcceptHeaderRequestCallback implements RequestCallback
//内部类,HttpEntityRequestCallback用于处理请求头和body,多用于发送POST,PUT请求。
2、private class HttpEntityRequestCallback extends AcceptHeaderRequestCallback
上面有个属性messageConverters ,里面都是一些请求或者收到回调数据的序列化和反序列化用到的对象,主要包含一下几大类。
ByteArrayHttpMessageConverter – 转换 byte array 类型数据
StringHttpMessageConverter – 根据编码格式,转化Strings
ResourceHttpMessageConverter – converts org.springframework.core.io.Resource for any type of octet stream
SourceHttpMessageConverter – 转换 javax.xml.transform.Source 类型的数据。
FormHttpMessageConverter – 转换 application/x-www-form-urlencoded 和 multipart/form-data 类型的消息.
Jaxb2RootElementHttpMessageConverter – 将对象和xml转换。
MappingJackson2HttpMessageConverter – 使用 jackson2 转换 json 数据和 对象实例
在创建RestTemplate的时候,如果用的是无参构造方法,那么默认会使用SimpleBufferingClientHttpRequest创建requestFactory,当然我们也可以指定不同的主要包含一下几种。(requestFactory是用于创建request的工厂)
SimpleBufferingClientHttpRequest --默认使用,
OkHttp3ClientHttpRequest
OkHttp3AsyncClientHttpRequest
Netty4ClientHttpRequestFactory
MockMvcClientHttpRequestFactory
请求的核心代码
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);//1.获取request
if (requestCallback != null) {
requestCallback.doWithRequest(request); //2.处理request
}
response = request.execute(); //3.执行
handleResponse(url, method, response); //错误处理
return (responseExtractor != null ? responseExtractor.extractData(response) : null); //5.解析response
}
.............
}
2、VarArgsTemplateVariables
这个主要存的是请求的参数,类的大致结构
//UriTemplateVariables包含请求url和对url进行处理的一些方法。
VarArgsTemplateVariables implements UriTemplateVariables{
//这是一个迭代器。例如在get请求的时候,方法里面会传多个参数,然后会把这些参数塞到这个迭代器里面去。
private final Iterator<Object> valueIterator;
}
url被处理后会被存到下面的类里面去。
//请求的url都会被拆分,http,端口,后面后面的地址,以及url后面参数变量。
HierarchicalUriComponents extends UriComponents {
private final String userInfo;
private final String host; //请求域名或者IP地址
private final String port; //端口号
private final PathComponent path; //请求路径
private final MultiValueMap<String, String> queryParams; //参数
private final EncodeState encodeState; //编码格式
private UnaryOperator<String> variableEncoder; //这个不知道。
}
继承UriTemplateHandler的还有很多入比如
public class DefaultUriBuilderFactory implements UriBuilderFactory extends UriTemplateHandler
public abstract class AbstractUriTemplateHandler implements UriTemplateHandler
public class RootUriTemplateHandler implements UriTemplateHandler
3、DefaultUriBuilderFactory
包含属性
//属性,如果是这种类型就会对UriComponentsBuilder设置编码格式(UTF-8)
private EncodingMode encodingMode = EncodingMode.TEMPLATE_AND_VALUES;
//属性
private final UriComponentsBuilder baseUri;
案例1:通过ClientHttpRequestInterceptor来自定义http请求拦截器,实现往请求Header里面添加参数。
先实现ClientHttpRequestInterceptor
public class TokenInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
String token = "xxxxxxxxxxxxx";
request.getHeaders().add("token-ali",token);
return execution.execute(request, body);
}
}
将Interceptor添加到RestTemplate中
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
//向restTemplate中添加自定义的拦截器
restTemplate.getInterceptors().add(new TokenInterceptor());
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://wwww.baidu.com", String.class);
}
总结:为什么使用RestTemplate有几大优点
1、可以手动指定转换器(HttpMessageConverter),按照我们的意愿转成对应的数据格式。
2、设置底层连接方式以及连接时长
3、设置拦截器(ClientHttpRequestInterceptor)
如果有什么疑惑可以看看下面的文章
参考1:https://blog.csdn.net/weixin_42083242/article/details/85785811
参考2:https://www.jianshu.com/p/90ec27b3b518