目录
RestTemplate 是 Spring 提供的,用于访问Rest服务的同步客户端,提供了一些简单的模板方法API;底层支持多种Http客户端类库,因为RestTemplate只是对其他的HTTP客户端的封装,其本身并没有实现HTTP相关的基础功能,底层实现可以按需配置;常用的有:
如果向查看所有的http客户端类库,可以找下ClientHttpRequestFactory接口的实现类:
RestTemplate、Apache的HttpClient、OkHttp比较:
这一块主要讲一些常用的方法及参数、对于一些重载的方法,其实原理都差不多。
除了getForEntity和getForObject外,使用exchange()也可以,前两个是基于它实现的,此处不做介绍
参数包括请求url、响应类型的class、请求参数
// 不带参数的
String url = "localhost:8001/test/method";
Object object = restTemplate.getForObject(url, Object.class);
// 带参数的,使用@PathVariable接收
String url = "localhost:8001/test/method/{param1}";
Object object = restTemplate.getForObject(url, Object.class, "param");
// 带参数的,使用@Requestparam接收
String url = "localhost:8001/test/method?param={dd}";
ResponseEntity
参数和get请求的相比,就多了第二个参数(Object request),如果使用最后一个参数传参时,和get请求类似,request设置为null就可以,如果使用第二个参数传参时,就需要考虑request的类型,request参数类型必须是实体对象、MultiValueMap、HttpEntity对象的的一种,其他不可以!!!
// 使用MultiValueMap传参
String url = "localhost:8001/test/method";
MultiValueMap map= new LinkedMultiValueMap<>(); // 不能使用HashMap,源码中会讲!
map.add("param1", "string1");
map.add("param2", "string2");
ResponseEntity response = restTemplate.postForEntity(url, map , String.class );
// 使用HttpEntity传参
String url = "localhost:8001/test/method";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add(HttpHeaders.CONTENT_ENCODING, StandardCharsets.UTF_8.toString());
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
String string = "param";
HttpEntity entity = new HttpEntity(string,headers);
String result = restTemplate.postForObject(url, entity, String.class);
org.springframework.boot
spring-boot-starter-web
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(@Qualifier("simpleClientHttpRequestFactory") ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);
factory.setConnectTimeout(5000);
return factory;
}
}
@Service
public class TestService implements ITestService {
@Autowired
RestTemplate restTemplate;
@Override
public ResultVo test() throws Exception {
try {
String url = "http://localhhost:9001/test/demo1";
ResponseEntity
思考重点:
1. 第二个参数为什么不能直接使用HashMap,而只能使用MultiValueMap?
2. 接收参数时,怎么合理的使用@RequestBody和@RequestParam?
3. restTemplate底层默认使用的是SimpleClientHttpRequestFactory,为什么不支持调用Https接口?
可以看到,三个构造方法,上边两个调用的是最下边一个;
第一个传入的是泛型,也就是传入的Object对象
第二个传入的是MultiValueMap,这个值是存放Headers的
所有只需要关注这个泛型,在哪块使用的
接下来会遍历所有的HttpMessageConverter,这些对象在RestTemplate的构造函数中被初始化
在遍历过程中判断是否可以写入,如果能写入则执行写入操作并返回;判断MessageConvertor是否为GenericHttpMessageConverter的子类,是因为写入的方式不同;在这些MessageConvertor中只有GsonHttpMessageConverter是GenericHttpMessageConverter的子类,且排在最后;因此,遍历过程中会先判断前六个convertor,能写入则执行写入,最后才是GsonHttpMessageConvertor。分析所有的HTTPMessageConvertor,可以发现
MultiValueMap子类的数据会被AllEncompassingFormHttpMessageConverter处理,将MediaType置为application/x-www-form-urlencoded、将request中的key value通过&=拼接并写入到body中,接收时,可以为@RequestParam、也可以为@RequestBody Http协议中,如果不指定Content-Type,则默认传递的参数就是application/x-www-form-urlencoded类型
HashMap类型的数据会被GsonHTTPMessageConvertor处理,将MediaType置为application/json;charset=UTF-8、将request转成json并写入到body中,因此,第二个参数设置为HashMap时,无法设置ContentType值,所有第二个参数无法使用HashMap!但是可以使用HttpEntity对象,将HashMap存放在HttpEntity对象里边,接收参数时,使用@RequestBody
restTemplate底层默认使用的是SimpleClientHttpRequestFactory,是基于HttpURLConnection,是不支持调用Https接口的,可以修改为HttpComponentsClientHttpRequestFactory
public class RestTemplateConfig {
@Bean
public RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1"},
null,
NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
}
以前工作中经常使用,但是时不时的就会出现问题,每次都是盲目的百度解决,趁着周末空余时间,详细的学习一下下,如果有不对的地方或者疑问,请大家指正,一起讨论。
分类: spring-boot