Spring Boot使用RestTemplate消费REST服务的几个问题记录

我们可以通过Spring Boot快速开发REST接口,同时也可能需要在实现接口的过程中,通过Spring Boot调用内外部REST接口完成业务逻辑。

在Spring Boot中,调用REST Api常见的一般主要有两种方式,通过自带的RestTemplate或者自己开发http客户端工具实现服务调用。

RestTemplate基本功能非常强大,不过某些特殊场景,我们可能还是更习惯用自己封装的工具类,比如上传文件至分布式文件系统、处理带证书的https请求等。

本文以RestTemplate来举例,记录几个使用RestTemplate调用接口过程中发现的问题和解决方案。

一、RestTemplate简介

1、什么是RestTemplate

我们自己封装的HttpClient,通常都会有一些模板代码,比如建立连接,构造请求头和请求体,然后根据响应,解析响应信息,最后关闭连接。

RestTemplate是Spring中对HttpClient的再次封装,简化了发起HTTP请求以及处理响应的过程,抽象层级更高,减少消费者的模板代码,使冗余代码更少。

其实仔细想想Spring Boot下的很多XXXTemplate类,它们也提供各种模板方法,只不过抽象的层次更高,隐藏了更多细节而已。

顺便提一下,Spring Cloud有一个声明式服务调用Feign,是基于Netflix Feign实现的,整合了Spring Cloud Ribbon与 Spring Cloud Hystrix,并且实现了声明式的Web服务客户端定义方式。

本质上Feign是在RestTemplate的基础上对其再次封装,由它来帮助我们定义和实现依赖服务接口的定义。

2、RestTemplate常见方法

常见的REST服务有很多种请求方式,如GET,POST,PUT,DELETE,HEAD,OPTIONS等。RestTemplate实现了最常见的方式,用的最多的就是Get和Post了,调用API可参考源码,这里列举几个方法定义(GET、POST、DELETE):

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) 

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)

public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,Object... uriVariables)

public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,Class<T> responseType, Object... uriVariables)

public void delete(String url, Object... uriVariables)

public void delete(URI url)

methods

同时要注意两个较为“灵活”的方法exchange和execute。

RestTemplate暴露的exchange与其它接口的不同:

(1)允许调用者指定HTTP请求的方法(GET,POST,DELETE等)

(2)可以在请求中增加body以及头信息,其内容通过参数‘HttpEntity<?>requestEntity’描述

(3)exchange支持‘含参数的类型’(即泛型类)作为返回类型,该特性通过‘ParameterizedTypeReference<T>responseType’描述。

RestTemplate所有的GET,POST等等方法,最终调用的都是execute方法。excute方法的内部实现是将String格式的URI转成了java.net.URI,之后调用了doExecute方法,doExecute方法的实现如下:

/**
* Execute the given method on the provided URI.
* <p>The {@link ClientHttpRequest} is processed using the {@link RequestCallback};
* the response with the {@link ResponseExtractor}.
* @param url the fully-expanded URL to connect to
* @param method the HTTP method to execute (GET, POST, etc.)
* @param requestCallback object that prepares the request (can be {@code null})
* @param responseExtractor object that extracts the return value from the response (can be {@code null})
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException { Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
else {
return null;
}
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
} doExecute

doExecute方法封装了模板方法,比如创建连接、处理请求和应答,关闭连接等。

多数人看到这里,估计都会觉得封装一个RestClient不过如此吧?

3、简单调用

以一个POST调用为例:

package com.power.demo.restclient;

import com.power.demo.common.AppConst;
import com.power.demo.restclient.clientrequest.ClientGetGoodsByGoodsIdRequest;
import com.power.demo.restclient.clientresponse.ClientGetGoodsByGoodsIdResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate; /**
* 商品REST接口客户端 (demo测试用)
**/
@Component
public class GoodsServiceClient { //服务消费者调用的接口URL 形如:http://localhost:9090
@Value("${spring.power.serviceurl}")
private String _serviceUrl; @Autowired
private RestTemplate restTemplate; public ClientGetGoodsByGoodsIdResponse getGoodsByGoodsId(ClientGetGoodsByGoodsIdRequest request) {
String svcUrl = getGoodsSvcUrl() + "/getinfobyid"; ClientGetGoodsByGoodsIdResponse response = null; try {
response = restTemplate.postForObject(svcUrl, request, ClientGetGoodsByGoodsIdResponse.class);
} catch (Exception e) {
e.printStackTrace();
response = new ClientGetGoodsByGoodsIdResponse();
response.setCode(AppConst.FAIL);
response.setMessage(e.toString());
} return response;
} private String getGoodsSvcUrl() { String url = ""; if (_serviceUrl == null) {
_serviceUrl = "";
}
if (_serviceUrl.length() == ) {
return url;
} if (_serviceUrl.substring(_serviceUrl.length() - , _serviceUrl.length()) == "/") {
url = String.format("%sapi/v1/goods", _serviceUrl);
} else {
url = String.format("%s/api/v1/goods", _serviceUrl);
} return url;
} } GoodsServiceClient

demo里直接RestTemplate.postForObject方法调用,反序列化实体转换这些RestTemplate内部封装搞定。

文献来源于: https://www.cnblogs.com/jeffwongishandsome/archive/2018/05/17/8995562.html

RestTemplateBuilder类的更多相关文章

  1. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

  2. Spring框架spring-web模块中的RestTemplate类详解

    RestTemplate类是spring-web模块中进行HTTP访问的REST客户端核心类.RestTemplate请求使用阻塞式IO,适合低并发的应用场景. 1. RestTemplate类提供了 ...

  3. C++ 可配置的类工厂

    项目中常用到工厂模式,工厂模式可以把创建对象的具体细节封装到Create函数中,减少重复代码,增强可读和可维护性.传统的工厂实现如下: class Widget { public: virtual i ...

  4. Android请求网络共通类——Hi_博客 Android App 开发笔记

    今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...

  5. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

    在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...

  6. ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

    背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...

  7. .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

    .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...

  8. Java基础Map接口+Collections工具类

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  9. PHP-解析验证码类--学习笔记

    1.开始 在 网上看到使用PHP写的ValidateCode生成验证码码类,感觉不错,特拿来分析学习一下. 2.类图 3.验证码类部分代码 3.1  定义变量 //随机因子 private $char ...

随机推荐

  1. web+下载文件夹

    文件下载的实质就是文件拷贝,将文件从服务器端拷贝到浏览器端,所以文件下载需要IO技术将服务器端的文件读取到,然后写到response缓冲区中,然后再下载到个人客户端. "> <m ...

  2. 【HTTP】无状态无连接的含义

    无连接:服务器处理完客户的请求,并收到客户的应答后,即断开连接. 早期这么做的原因是HTTP协议产生于互联网,因此服务器需要处理同时面向全世界数十万.上百万客户端的网页访问,但每个客户端(即浏览器)与 ...

  3. 小米oj 反向位整数(简单位运算)

     反向位整数 序号:#30难度:一般时间限制:1000ms内存限制:10M 描述 输入32位无符号整数,输出它的反向位. 例,输入4626149(以二进制表示为00000000010001101001 ...

  4. 我爱网络流之最大流Dinic

    直接上大佬博客: Dinic算法详解及实现来自小菲进修中 Dinic算法(研究总结,网络流)来自SYCstudio 模板步骤: 第一步,先bfs把图划分成分成分层图网络 第二步,dfs多次找增广路 当 ...

  5. 阿里云Ubuntu安装LNMP环境之PHP7

    在QQ群很多朋友问阿里云服务器怎么安装LNMP环境,怎么把项目放到服务器上面去,在这里,我就从头开始教大家怎么在阿里云服务器安装LNMP环境. 在这之前,我们先要知道什么是LNMP. L: 表示的是L ...

  6. IDEA2019.1.3的安装和破解

    上一篇文章我有写过我会尝试安装IDEA(这玩意儿收费啊!),倘若尝试成功以后都会用它编译,很幸运,我安装成功了,所以今天这篇文章我来写安装和破解方法. IDEA界面: ​ 首先我们访问官方网站:htt ...

  7. Spring AOP:Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException

    1 报错 Exception encountered during context initialization - cancelling refresh attempt: org.springfra ...

  8. js判断是否联网

    // navigator.onLine if (navigator.onLine){ //正常工作 console.log("在线状态............................ ...

  9. 【log4j】log4j.properties 文件示例

    # 下面的文件内容是写程序长期要用的,放在这里留个底#Output information(higher than INFO) to stdout and file.info/debug/error ...

  10. RecyclerView进阶:使用ItemTouchHelper实现拖拽和侧滑删除

    现在RecyclerView的应用越来越广泛了,不同的应用场景需要其作出不同的改变.有时候我们可能需要实现侧滑删除的功能,比如知乎首页的侧滑删除,又或者长按Item进行拖动与其他Item进行位置的交换 ...