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. 05 vue项目01-组件关系、bootstrap

    1.django后端项目 1.项目预期 配置前端静态资源            页面展示 2.django项目代码 主url from django.contrib import admin from ...

  2. CodeForces 837D - Round Subset | Educational Codeforces Round 26

    /* CodeForces 837D - Round Subset [ DP ] | Educational Codeforces Round 26 题意: 选k个数相乘让末尾0最多 分析: 第i个数 ...

  3. 010_linuxC++之_运算符重载

    (一)运算符重载:运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型. (二)实现类不同对象里中变量的相加 (三)程序 #include <iostream> ...

  4. 7.20套娃(tao)

    套娃(tao) input7 39 53 710 65 102 610 104 110 53 53 9output012 sol: 把查询想象成(x1,y1)向(x2,y2)有边当且仅当(x1< ...

  5. c++中类的初次接触

    下面是我写的简单的代码,初次接触c++中的类,c++真的是博大精深啊,学习c++的路还很长,加油! /*q1.cpp*/ //一个简单的类极其实例化 #include<iostream> ...

  6. Linux查看进程的启动路径——pwdx

    想要找到transfer的启动路径. 一般是ps -ef | grep keyward 但是这个刚好是没有用绝对路径执行. 再用pwdx  pid获得

  7. 关于centos6版本执行程序报错:libc.so.6: version GLIBC_2.14 not found的解决

    执行后程序报错: libc.so.6: version GLIBC_2.14 not found 这种情况是因为当前服务器glibc的版本比较低造成的(不出意外是glibc_2.12是最高版本): 1 ...

  8. [51nod1789] 跑得比谁都快

    题面 题解 设\(f[i]\)为根节点到\(i\)的最小耗时 设\(S\)为\(i\)的祖先集合, 可以得到 \[ f[i] = min(f[j] + (i - j)^p),j \in S \] 对于 ...

  9. Linux 上的Tomcat配置输入域名直接访问项目

    申请的域名备案通过了,域名是在阿里云上面的买的,一块钱,当初买服务器是买着来玩玩的. 既然申请的域名已经备案通过了,也配置了域名解析 ,服务器上也装了Tomcat,部署了web项目,下面来配置下通过域 ...

  10. LeetCode 160. 相交链表(Intersection of Two Linked Lists)

    题目描述 编写一个程序,找到两个单链表相交的起始节点. 例如,下面的两个链表: A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3 在节点 c1 开始相交. 注意: ...