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. 包过滤防火墙iptables(网络层)

    安装: yum -y install iptables-services 启动:systemctl start iptables.service 四表五链 过滤:filter - input forw ...

  2. c 判断一个字符是否为字母

    #include <stdio.h> #include <wctype.h> int main () { ; wchar_t str[] = L"C++"; ...

  3. POJ 1144 Network —— (找割点)

    这是一题找无向图的割点的模板题,割点的概念什么的就不再赘述了.这里讲一下这个模板的一个注意点. dfs中有一个child,它不等于G[u].size()!理由如下: 如上图,1的size是2,但是它的 ...

  4. Asyncio之EventLoop笔记

    使用事件循环 Python3.4 采用了一个强大的框架来支持代码的并发执行: asyncio.这个框架使用事件循环来编排回调和异步任务. 事件循环位于事件循环策略的上下文中-这是 asyncio 所特 ...

  5. Leetcode题目226.翻转二叉树(简单)

    题目描述: 翻转一颗二叉树 示例: 输入: 4 / \ 2 7 / \ / \ 1 3 6 9 输出: 4 / \ 7 2 / \ / \ 9 6 3 1 思路分析: 1)递归,不断交换左右子树,直到 ...

  6. 求两个排序数组的交集和并集----时间复杂度O(n+m)

    问题: 给你两个排序的数组,求两个数组的交集. 比如: A = 1 3 4 5 7, B = 2 3 5 8 9, 那么交集就是 3 5,n是a数组大小,m是b数组大小. 思路: (1)从b数组遍历取 ...

  7. 单调队列优化dp,k次移动求最长路

    洛谷2254 给你k次移动 每次移动给你一个时间段 a,b和方向dir 地图上有障碍物 为了不撞上障碍物你可以施法让箱子停下来 问箱子可以走的最长路 ((以下是洛谷的题解)) /*首先考虑对于时间t来 ...

  8. 码支付(php版本)应用

    1.下载软件 2.安装php 版本 2.打开软件,登陆支付宝 3.codepay_config.php  中填写逻辑代码 4.充值路径: 说明:$username = trim($_GET['user ...

  9. 负载均衡 | Nginx+Tomcat 动静分离实现负载均衡

    0.前期准备 使用Debian环境.安装Nginx(默认安装),一个web项目,安装tomcat(默认安装)等. 1.一份Nginx.conf配置文件 基本配置这个文件,就可以实现负载了.但是里面的各 ...

  10. 提高组刷题营 DAY 2

    1.滞空(jump/1s/64M) #include<bits/stdc++.h> using namespace std; typedef long long LL; ; inline ...