RestTemplate

简介

  • RestTemplate是由Spring框架提供的一个可用于应用中调用rest服务的类它简化了与http服务的通信方式,统一了RESTFul的标准,封装了http连接,我们只需要传入url及其返回值类型即可。相较于之前常用的HttpClientRestTemplate是一种更为优雅的调用RESTFul服务的方式。
  • Spring应用程序中访问第三方REST服务与使用Spring RestTemplate类有关。RestTemplate类的设计原则与许多其他Spring的模板类(例如JdbcTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。
  • RestTemplate默认依赖JDK提供了http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如Apache HttpCompoent、Netty或OKHttp等其他Http libaray
  • 考虑到了RestTemplate类是为了调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了,后者时HTTP协议的方法:HEAD、GET、POST、PUT、DELETE、OPTIONS例如,RestTemplate类具有headForHeaders()、getForObject()、putForObject(),put()和delete()等方法。

创建RestTemplate

​ 因为RestTemplateSpirng框架提供的所以只要是一个Springboot项目就不用考虑导包的问题,这些都是提供好的。

​ 但是Spring并没有将其加入SpringBean容器中,需要我们手动加入,因为我们首先创建一个Springboot配置类,再在配置类中将我们的RestTemlate注册到Bean容器中

方法一

​ 使用Springboot提供的RestTemplateBuilder构造类来构造一个RestTemplate,可以自定义一些连接参数,如:连接超时时间,读取超时时间,还有认证信息等

@Configuration
public class WebConfiguration {@Beanpublic RestTemplate restTemplate(RestTemplateBuilder builder){return builder//设置连接超时时间.setConnectTimeout(Duration.ofSeconds(5000))//设置读取超时时间.setReadTimeout(Duration.ofSeconds(5000))//设置认证信息.basicAuthentication("username","password")//设置根路径.rootUri("https://api.test.com/")//构建.build();}
}

添加自定义的拦截器

​ 自定义拦截器示例

@Slf4j
public class CustomClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {//打印请求明细logRequestDetails(request,body);ClientHttpResponse response = execution.execute(request, body);//打印响应明细logResponseDetails(response);return response;}private void logRequestDetails(HttpRequest request, byte[] body){log.debug("Headers:{}",request.getHeaders());log.debug("body:{}",new String(body, StandardCharsets.UTF_8));log.debug("{}:{}",request.getMethod(),request.getMethodValue());}private void logResponseDetails(ClientHttpResponse response) throws IOException {log.debug("Status code : {}",response.getStatusCode());log.debug("Status text : {}",response.getStatusText());log.debug("Headers : {}",response.getHeaders());log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(),StandardCharsets.UTF_8));}
}

​ 使用RestTemplateBuilder构造类,添加自定义拦截器,构造带有自定义拦截器的RestTemplate实例

@Configuration
public class WebConfiguration {@Beanpublic RestTemplate restTemplate(RestTemplateBuilder builder){return builder.additionalInterceptors(new CustomClientHttpRequestInterceptor())//构建.build();}
}

​ 测试请求确实经过了拦截器,注册成功(注意请求和响应的流只会被读取一次,这里我们读取了response后返回的response就读取不到刚刚读过的内容了)


方法二

​ 使用RestTemplate构造方法构造一个RestTemlate,虽然不能像RestTemplate构造类那样更详细、更多样的配置参数,但是RestTemplate构造方法在一般情况是够用的。

  • 无参构造 全部参数默认
  • 指定ClientHttpRequestFactory 的构造方法可以指定自己实现的ClientHttpRequestFactory(客户端http请求工厂)其他的与无参构造相同。
    • ClientHttpRequestFactory
  • 指定List<HttpMessageConverter<?>>的构造方法可以指定自己是实现的HttpMessageConverterHttp消息转换器)传入其他与无参构造相同。
@Configuration
public class WebConfiguration {@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}}

​ 两者方法都可使用,前者提供了多样的自定义参数的选择,可以将RestTemplate配置的更为完善,后者则简化了配置虽然配置多样性不如前者,但是日常使用调用些API还是足以使用

RestTemplate API使用

​ 在使用RestTemplate前先让我们看看RestTemplate有哪些API

​ 相信大家看到这么多方法,一定很头大,但是我们仔细看上述的方法,我们可以提取出主要的几种方法是(这里只讨论Http请求的):

  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • OPTIONS
  • EXCHANGE
  • EXECUTE

这里我给大家安利一个一个网站,它提供免费的RESTFul api的样例测试。httpbin A simple HTTP Request & Response Service.


GET

​ 通过上图我们可以发现RestTemlate发送GET请求的方法有两种

  • public <T> T getForObject(...)
  • public <T> ResponseEntity<T> getForEntity(...)

getForEntity()

​ 后缀带有Entity的方法都代表返回一个ResponseEntity<T>ResponseEntity<T>是Spring对HTTP请求响应的封装,包括了几个重要的元素,如响应码,contentType、contentLength、响应消息体等

​ 通过它继承父类(HttpEntity<T>)的getHeader()方法我们可以获取contentType、contentLength、响应消息体等。比如下面这个例子。

public void queryWeather() {ResponseEntity<Object> forEntity = restTemplate.getForEntity("https://restapi.amap.com/v3/weather/weatherInfo?city=510100&key=e7a5fa943f706602033b6b329c49fbc6", Object.class);System.out.println("状态码:"+forEntity.getStatusCode());System.out.println("状态码内容:"+forEntity.getStatusCodeValue());HttpHeaders headers = forEntity.getHeaders();System.out.println("响应头:"+headers);Object body = forEntity.getBody();System.out.println("响应内容:"+body);}

​ 该例子中getForEntity()方法的第一个参数为我要调用服务的URL,第二个参数则为响应内容的类的类型(Java嘛 万物皆对象)还可以添加第三个参数,第三个参数为一个可变参数 代表着调用服务时的传参。

第三个参数可以使用key-value的map来传入参数

get请求也可通过向在url上添加查询参数来发送带有请求的参数


getForObject()

​ 相比于前者getForEntity()该方法则是,更偏向于直接获取响应内容的,因为他直接返回响应实体的body(响应内容),。比如下面这个例子

public void queryWeather() {Object body = restTemplate.getForObject("https://restapi.amap.com/v3/weather/weatherInfo?city=510100&key=e7a5fa943f706602033b6b329c49fbc6", Object.class);System.out.println(body);}
方法参数签名与`getForEntity()`基本一致。

​ 当你只需要返回的响应内容时,使用getForObject()是一个很好的选择,但当你需要获得更详细的响应信息,如响应头中的信息,你就只能选择getForEntity()了。


POST

POST请求有如下三种方法

  • public URI postForLocation(...)
  • public <T> T postForObject(...)
  • public <T> ResponseEntity<T> postForEntity(...)

​ 后两种用法与GET基本一致不做详细介绍,这里着重介绍postForLocation()


postForEntity()

​ 该方法有三个参数,第一个为调用服务的地址(URL)

​ 第二个参数表示上传的参数(json格式提交)

​ 第三个表示返回响应内容的具体类型

​ 第四个参数也用于指定参数(在URL中添加)

@Overridepublic void queryWeather() {User user = new User();user.setName("鲁大师");ResponseEntity<Object> objectResponseEntity = restTemplate.postForEntity("https://restapi.amap.com/v3/weather/weatherInfo?city=510100&key=e7a5fa943f706602033b6b329c49fbc6", user, Object.class);System.out.println("消息响应内容:"+objectResponseEntity.getBody());}

postForObject()

​ 使用方法与getForObject类似只是多了一个传入对象参数(传入方式与postForEntity()相同)

public void queryWeather() {User user = new User();user.setName("鲁大师");ResponseEntity<Object> objectResponseEntity = restTemplate.postForEntity("https://httpbin.org/post", user, Object.class);MediaType contentType = objectResponseEntity.getHeaders().getContentType();System.out.println(contentType);System.out.println("消息响应内容:"+objectResponseEntity.getBody());}

postForLocation()

postForLocation传参用法与前两者一致,只不过返回从实体变成了一个URL,因此它不需要指定返回响应内容的类型。

public void queryWeather() {User user = new User();user.setName("鲁大师");URI uri = restTemplate.postForLocation("https://httpbin.org/post", user);System.out.println(uri);}

这个只需要服务提供者返回一个 URI 即可,该URI返回值体现的是:用于提交完成数据之后的页面跳转,或数据提交完成之后的下一步数据操作URI

使用POST以表单方式提交

​ 这里我们着重说一下,如何自己封装一个请求体。

​ 我们需要用到如下几个类

  • HttpHeaders
  • MultiValueMap<K,V>
  • HttpEntity<T>
HttpHeaders

​ 故名思意,就是用来封装Http请求的请求头的,这里我们要设置他的ContentType为**MediaType.APPLICATION_FORM_URLENCODED**以使得我们提交的参数是以Form(表单)的形式提交。

//设置请求头, x-www-form-urlencoded格式的数据HttpHeaders httpHeaders = new HttpHeaders();//这里指定参数以UTF-8编码格式传输MediaType mediaType = new MediaType(MediaType.APPLICATION_FORM_URLENCODED, UTF_8);httpHeaders.setContentType(mediaType);//提交参数设置MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("name","鲁大师");

MultiValueMap<K,V>

​ 该类是用来封装请求参数的,是以key-value的形式封装但是以单个key对应多个value的格式传输(也就是是以单个key:[value...]的格式传输的)。

//提交参数设置MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("name","鲁大师");

如果像传输单个key对应单个value使用普通的Map传参即可


HttpEntity<T>

​ 该类是用来封装请求的,主要作用就是将请求头和请求体封装在一起成为一个请求实体 T用来指定用来封装参数的容器的类型。

//组装请求体HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, httpHeaders);

测试

通过上述介绍后,我们就可以自己封装一个以form形式提交参数的POST请求了。

@Testvoid contextLoads() {//请求地址String url = "https://httpbin.org/post";//设置请求头, x-www-form-urlencoded格式的数据HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);//提交参数设置MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("name","鲁大师");//组装请求体HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, httpHeaders);//发送post请求并打印结果 以String类型接收响应结果JSON字符串String s = restTemplate.postForObject(url, request, String.class);System.out.println(s);}

​ 通过拦截器拦截了请求并对请求头进行拆包,可以发现ContentType已经被修改成了x-www-form-urlencoded格式了。

PUT

PUT请求的方法只有一类

  • void put()

PUT()

​ 使用方法与postForEntity()参数基本一致,只是put方法没有返回值(也就不必去设置响应内容的类型了)。

@Testvoid contextLoads() {//请求地址String url = "http://httpbin.org/put";User user = new User();user.setName("鲁大师");restTemplate.put(url,user);}

DELETE

​ 与PUT一样,DELETE方法只有一类

  • void delete()

delete()

delete()可以指定url中的中的参数,但是RestTemplatedelete()方法是不支持上传requestBody的。

void contextLoads() {//请求地址String url = "http://httpbin.org/delete";restTemplate.delete(url);
}

HEADER

HEADER也只有一类方法

  • public HttpHeaders headForHeaders()

​ 主要用来发送请求获取响应头部信息,但是像DELETEPUT这类没有响应的方法,是不能使用该方法的(因为没有响应也就没有响应头了)。

@Testvoid contextLoads() {//请求地址String url = "http://httpbin.org/get";HttpHeaders httpHeaders = restTemplate.headForHeaders(url);System.out.println(httpHeaders);}


OPTIONS

  • public Set<HttpMethod> optionsForAllow()

​ 该方法的主要用来判断该服务地址,能够使用那种方法去执行

 @Testvoid contextLoads() {//请求地址String url = "http://httpbin.org/get";Set<HttpMethod> httpMethods = restTemplate.optionsForAllow(url);System.out.println(httpMethods);}


EXCHANGE

  • <T> ResponseEntity<T> exchange()

​ 该接口与其他接口不同

  • 该方法允许用户指定请求的方法(get,post,put等)
  • 可以在请求中增加body以及头信息,其内容通过参数HttpEntity<?> requestEntity描述
  • exchange支持’含参数的类型(即泛型)'作为返回类型,该特性通过ParameterizedTypeReferenceresponseType 描述

​ 该方法支持五个参数

  • 第一个是服务地址
  • 第二个是请求方法
  • 第三个是写入的请求实体
  • 第四个是响应内容的类型
  • 第五个是扩展模板的变量或包含URI模板变量的映射
@Test
void contextLoads() {//请求地址String url = "http://httpbin.org/post";User user = new User();user.setName("彭于晏");HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.setContentType(MediaType.APPLICATION_JSON);HttpEntity<User> userHttpEntity = new HttpEntity<>(user, httpHeaders);ResponseEntity<Object> exchange = restTemplate.exchange(url, HttpMethod.POST, userHttpEntity, Object.class);System.out.println(exchange);
}

​ 上述代码模拟了一个简单的POST请求 可以理解为可以动态的指定请求方法和请求实体的一个方法。

响应实体


EXECUTE

  • <T> T execute()

​ 该方法就是执行请求的方法,我们可以发现上述的所有方法的最后执行都是调用的该方法执行,所以他在RestTemplate中十分重要

​ 该方法有五个参数

  • 服务地址
  • 请求的方法
  • 准备请求的对象(requestCallback
  • 从响应中提取返回值的对象
  • 扩展模板的变量或包含URI模板变量的映射

execute()

@Override@Nullablepublic <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {URI expanded = getUriTemplateHandler().expand(url, uriVariables);return doExecute(expanded, method, requestCallback, responseExtractor);}

​ 通过上述源码我们可以发现execute()方法只是将我们传入的String类型的URL转换为了URL类型,最后执行请求是由doExecute()方法


doExecute()

​ 这里需要了解两个类:RequestCallbackResPonseExtractor

RequestCallback: 用于操作请求头和body,在请求发出前执行。不需要关心关闭请求或处理错误:这都将由RestTemplate处理。

​ 该接口有两个实现类:

ResPonseExtractor: 解析HTTP响应的数据,而且不需要担心异常和资源的关闭。

​ 该接口在RestTemplate中同样有两个实现类:

HeadersExtractor 提取响应HttpHeaders的响应提取器。直接提取响应体中的响应头
ResponseEntityResponseExtractor<T> HttpEntity的响应提取器。可以获取响应实体里面包括响应头,响应体等。具体请查看HttpEntity
@Test
void contextLoads() {//请求地址String url = "http://httpbin.org/post";User user = new User();user.setName("彭于晏");HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.setContentType(MediaType.APPLICATION_JSON);HttpEntity<User> userHttpEntity = new HttpEntity<>(user, httpHeaders);ResponseEntity<Object> execute = restTemplate.execute(url, HttpMethod.POST, restTemplate.httpEntityCallback(userHttpEntity), restTemplate.responseEntityExtractor(Object.class));System.out.println(execute);
}


解惑

  • 前面我们介绍方法的时候发现有个一个可变参数,那个参数被描述成了扩展模板的变量或是包含URI模板变量的映射

我们来简单看一下这个参数,我们知道请求传参可以通过url拼接参数的方式传参,拼接参数也分为两种:

  • 路径中嵌入占位的格式(http://httpbin.org/{1}/post)也叫模板映射
  • 末尾添加Key-value格式(http://httpbin.org/post?name="彭于晏")即扩展模板的变量
  • 当我们最后一参数传入map时会以key-value的格式拼接在URL后(通俗的说就是这样设置的变量会跟着URL路径后面)

http://httpbin.org/post?name="彭于晏"

@Test
void contextLoads() {//请求地址String url = "http://httpbin.org/get";HashMap<String, String> map = new HashMap<>();map.put("name","彭于晏");Object forObject = restTemplate.getForObject(url, Object.class, map);System.out.println(forObject);
}
  • 当我们传入简单的对象如String,Integer时且路径中有嵌入的占位符时就会代替调用URL中占位符
@Test
void contextLoads() {//请求地址String url = "http://httpbin.org/{2}/get";HashMap<String, String> map = new HashMap<>();Object forObject = restTemplate.getForObject(url, Object.class, 99);System.out.println(forObject);
}


参考

spring cloud 做微服务时关于RestTemplate中的各种请求方法的使用总结_DWT_CCFK的博客-CSDN博客

RestTemplate 详解 - 知乎 (zhihu.com)

RestTemplate使用教程 - 简书 (jianshu.com)


-End-

RestTemplate相关推荐

  1. restTemplate http请求报错:no suitable HttpMessageConverter found for response type and content type

    报错信息: org.springframework.web.client.UnknownContentTypeException: Could not extract response: no sui ...

  2. SpringCloud Alibaba微服务实战(二) - Nacos服务注册与restTemplate消费

    说在前面 基础环境搭建,理论,请看上一篇,在这就不扯理论了,直接上代码. 项目结构 代码实现 第一步:在父pom的项目中引入dependencyManagement 在引入父pom之前咱们先来回顾下d ...

  3. 运行一段时间后,RestTemplate请求报400错误

    问题描述 本地调用远端接口无误,部署到服务器上调用刚开始也无误,随着时间的推移,调用次数的增加,再次调用时报 400 Bad Request 错误. 问题代码 private String sendR ...

  4. Http请求之优雅的RestTemplate

    前言 本篇博客为对RestTemplate总结 HttpURLConnection 在讲RestTemplate之前我们来看看再没有RestTemplate之前是怎么发送http请求的. privat ...

  5. java rest httpclient_java http请求建议使用webClient,少用RestTemplate,不用HttpClient

    简介: webClient:是Spring-webFlux包下的,非阻塞响应,最低java8支持函数式编程,性能好 RestTemplate:是Spring-webmvc包下的,满足RestFul原则 ...

  6. Spring Boot 中的 RestTemplate不好用?试试 Retrofit !

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | 六点半起床 来源 | juejin.im/post/68 ...

  7. SpringBoot第十六篇:用restTemplate消费服务

    这篇文章主要介绍怎么用消费一个 Restful的web服务.我将用restTemplate去消费一个服务: http://gturnquist-quoters.cfapps.io/api/random ...

  8. Spring Cloud第二篇:服务消费者RestTemplate+Ribbon

    在上一篇文章,讲了服务的注册和发现.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+r ...

  9. java get resttemplate 请求传递数组_RestTemplate入门

    RestTemplate入门  本篇主要讲解RestTemplate的基本使用,它是Spring提供的用来访问Rest服务的客户端,RestTmplate提供了很多便捷的方法,可以大大提供开发效率,本 ...

  10. 详解 RestTemplate 操作

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/xmt1139057136/article/details/82761642 作为开发人员,我们经常关 ...

最新文章

  1. dubbo服务者配置说明
  2. Go语言Flag的简单示例
  3. S3C2440时钟体系结构
  4. Hibernate Validator用法
  5. Spring Boot 10:处理Json数据中的null值
  6. 听说这家云计算公司要搞事情
  7. dsp31段最佳调音图_均衡器如何使用_31段均衡器调整方法
  8. 颜值经济风暴来袭,国产美容仪如何站稳脚跟?
  9. Tracert(traceroute)Ping 工作原理分析
  10. 如何下载VS2015社区版
  11. 2012年8月至今读书列表 --- 持续更新
  12. 分子动力学理论部分总结(未整理完)
  13. 流行音乐表明我们的注意力越来越短
  14. Nginx+Tomcat 搭建负载均衡、动静分离(tomcat多实例)
  15. 英特尔前任 CEO 安迪·格鲁夫的传奇一生
  16. PHP redis配置说明
  17. 华为fusion超融合虚拟服务器,华为FusionCube超融合:满足客户未来一切云化所需...
  18. hiper – web_Web设计行业分析–专业人士与业余者[信息图]
  19. ”linux学习之路” (感觉写的很好,更像是网络编程学习路线图)
  20. U盘打不开? U盘数据怎么恢复?

热门文章

  1. 企业级低代码平台,接私活必备的Java开源项目(附源码)
  2. 重磅!百度网盘新规发布:将收回已获得的免费空间!网友炸裂了
  3. 英格索兰整体解决方案助力汽车制造行业不断升级
  4. 德慎思信息安全OWASP系列之OWASP TOP 10
  5. wxpython文档_wxPython笔记
  6. 浅谈Java等软件和嵌入式的区别,给你明确一个方向
  7. android 中国首发 安卓发布应用市场图片准备 是否需要软著 加固
  8. 局域网 广域网 网际网络
  9. 你了解的计算机网络知识有哪些?
  10. Linux shutdown命令:关机和重启