首页 文章资讯内容详情

Spring RestTemplate详解

2026-06-01 2 花语

本文内容纲要:

-1、什么是REST? -2、REST成熟度的四个层次 -3、HTTP请求的方法 - -4、HTTP请求的状态码 -5、RestTemplate -5.1简介 -5.2对外开放的接口 -(2)每一个小类又分三种,这三种有什么区别? -(3)Exchange -(4)excute -6.doExcute

1、什么是REST?

REST(RepresentationalStateTransfer)是RoyFielding提出的一个描述互联系统架构风格的名词。REST定义了一组体系架构原则,您可以根据这些原则设计以系统资源为中心的Web服务,包括使用不同语言编写的客户端如何通过HTTP处理和传输资源状态。

为什么称为REST?Web本质上由各种各样的资源组成,资源由URI唯一标识。浏览器(或者任何其它类似于浏览器的应用程序)将展示出该资源的一种表现方式,或者一种表现状态。如果用户在该页面中定向到指向其它资源的链接,则将访问该资源,并表现出它的状态。这意味着客户端应用程序随着每个资源表现状态的不同而发生状态转移,也即所谓REST。

附:REST定义、REST与SOAP的比较

2、REST成熟度的四个层次

第一个层次(Level0)的Web服务只是使用HTTP作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP和XML-RPC都属于此类。

第二个层次(Level1)的Web服务引入了资源的概念。每个资源有对应的标识符和表达。

第三个层次(Level2)的Web服务使用不同的HTTP方法来进行不同的操作,并且使用HTTP状态码来表示不同的结果。如HTTPGET方法来获取资源,HTTPDELETE方法来删除资源。

第四个层次(Level3)的Web服务使用HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。

其中第三个层次建立了创建、读取、更新和删除(create,read,update,anddelete,CRUD)操作与HTTP方法之间的一对一映射。根据此映射:

(1)若要在服务器上创建资源,应该使用POST方法。

(2)若要检索某个资源,应该使用GET方法。

(3)若要更改资源状态或对其进行更新,应该使用PUT方法。

(4)若要删除某个资源,应该使用DELETE方法。

3、HTTP请求的方法

(1)GET:通过请求URI得到资源

(2)POST:用于添加新的内容

(3)PUT:用于修改某个内容,若不存在则添加

(4)DELETE:删除某个内容

(5)OPTIONS:询问可以执行哪些方法

(6)HEAD:类似于GET,但是不返回body信息,用于检查对象是否存在,以及得到对象的元数据

(7)CONNECT:用于代理进行传输,如使用SSL

(8)TRACE:用于远程诊断服务器

4、HTTP请求的状态码

(1)成功Successful2xx:此类状态码标识客户端的请求被成功接收、理解并接受。常见如200(OK)、204(NoContent)。

(2)重定向Redirection3xx:这个类别的状态码标识用户代理要做出进一步的动作来完成请求。常见如301(MovedPermanently)、302(MovedTemprarily)。

(3)客户端错误ClientError4xx:4xx类别的状态码是当客户端象是出错的时使用的。常见如400(BadRequest)、401(Unauthorized)、403(Forbidden)、404(NotFound)。

(4)服务器错误ServerError5xx:响应状态码以5开头表示服务器知道自己出错或者没有能力执行请求。常见如500(InternalServerError)、502(BadGateway)、504(GatewayTimeout)。

附HTTP1.1的标准简介:http://blog.chinaunix.net/uid-9188830-id-2007021.html

5、RestTemplate

5.1简介

Springscentralclassforsynchronousclient-sideHTTPaccess.ItsimplifiescommunicationwithHTTPservers,andenforcesRESTfulprinciples.IthandlesHTTPconnections,leavingapplicationcodetoprovideURLs(withpossibletemplatevariables)andextractresults.

简单说就是:简化了发起HTTP请求以及处理响应的过程,并且支持REST。为什么说简化了呢?

来看两种实现方式

(1)使用java.net包下的URLConnection建立连接

[java]viewplaincopy

Stringresult=""; BufferedReaderin=null; try{ StringurlNameString=url+"?"+param; URLrealUrl=newURL(urlNameString); //打开和URL之间的连接 URLConnectionconnection=realUrl.openConnection(); //设置通用的请求属性 connection.setRequestProperty("accept","*/*"); connection.setRequestProperty("connection","Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1)"); //建立实际的连接 connection.connect(); //获取所有响应头字段 Map<String,List>map=connection.getHeaderFields(); //遍历所有的响应头字段 for(Stringkey:map.keySet()){ System.out.println(key+"--->"+map.get(key)); } //定义BufferedReader输入流来读取URL的响应 in=newBufferedReader(newInputStreamReader( connection.getInputStream())); Stringline; while((line=in.readLine())!=null){ result+=line; } }catch(Exceptione){ … } //使用finally块来关闭输入流 finally{ //关闭流 }

(2)使用RestTempalte

[java]viewplaincopy

ResponseEntityresult=restTemplate.getForEntity(requestPathUrl,SsoUrlPrm.class);

5.2对外开放的接口

(1)

DELETE delete GET getForObject getForEntity HEAD headForHeaders OPTIONS optionsForAllow POST postForLocation postForObject PUT put any exchange execute

(2)每一个小类又分三种,这三种有什么区别?

*第一种和第二种的首个参数都是用String表示一个URI。但它们的最后一个参数分别是Object[]和Map

*第三种的首个参数使用java.net.URI表示一个URI。且只有两个参数

这是因为,String类型的URI支持占位符。比如:

restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}",String.class,"42","21");

那么最终访问的URI为:http://example.com/hotels/42/bookings/21

但是String有一个小缺陷:String形式的URI会被URL编码两次(URLencode请自行百度),这就要求服务器在获取URI中的参数时主动进行一次解码,但如果服务的提供者不这么做呢?

这时就需要使用不会使用任何编码的java.net.URI

PS:参数‘ClassresponseType’定义了返回数据的类型。

(3)Exchange

与其它接口的不同:

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

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

exchange支持‘含参数的类型’(即泛型类)作为返回类型,该特性通过‘ParameterizedTypeReferenceresponseType’描述。比如:

[java]viewplaincopy

Lista=newArrayList(); System.out.println(a.getClass()); System.out.println(a.getClass().getGenericSuperclass()); ParameterizedTypeReferencept=newParameterizedTypeReference<ArrayList>(){}; System.out.println(pt.getType());

得到的结果是:

[java]viewplaincopy

classjava.util.ArrayList java.util.AbstractList java.util.ArrayList<java.lang.String>

*这是因为ParameterizedTypeReference<ArrayList>并不根据实参而是使用getGenericSuperclass()方法获取其父类的类型(注意这里的new有花括号,是ParameterizedTypeReference的子类),父类的类型通过java.lang.reflect.Type描述,然后通过Type的getActualTypeArguments()获得了父类的实参类型,注意得到的Type类,并不是class类。

(4)excute

所有的get、post、delete、put、options、head、exchange方法最终调用的都是excute方法。举个栗子:

[java]viewplaincopy

@Override publicTgetForObject(Stringurl,ClassresponseType,Object...urlVariables)throwsRestClientException{ RequestCallbackrequestCallback=acceptHeaderRequestCallback(responseType); HttpMessageConverterExtractorresponseExtractor= newHttpMessageConverterExtractor(responseType,getMessageConverters(),logger); returnexecute(url,HttpMethod.GET,requestCallback,responseExtractor,urlVariables); }

Excute方法只是将String格式的URI转成了java.net.URI,之后调用了doExecute方法。整个调用过程

6.doExcute

6.1定义

[java]viewplaincopy

protectedTdoExecute(URIurl,HttpMethodmethod,RequestCallbackrequestCallback,ResponseExtractorresponseExtractor)throwsRestClientException{…}

这里需要了解两个类:RequestCallback&ResponseExtractor

6.2RequestCallback

CallbackinterfaceforcodethatoperatesonaClientHttpRequest.Allowstomanipulatetherequestheaders,andwritetotherequestbody.

简单说:用于操作请求头和body,在请求发出前执行。

该接口有两个实现类:

AcceptHeaderRequestCallback 只处理请求头,用于getXXX()方法。 HttpEntityRequestCallback 继承于AcceptHeaderRequestCallback可以处理请求头和body,用于putXXX()、postXXX()和exchange()方法。

*DELETE、HEAD、OPTIONS没有使用这个接口。

6.3发起请求

6.4ResponseExtractor

6.4.1定义

GenericcallbackinterfaceusedbyRestTemplatesretrievalmethodsImplementationsofthisinterfaceperformtheactualworkofextractingdatafromaClientHttpResponse,butdontneedtoworryaboutexceptionhandlingorclosingresources.

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

该接口有三个实现类:

HeadersExtractor 用于提取请求头。 HttpMessageConverterExtractor 用于提取响应body。 ResponseEntityResponseExtractor 使用HttpMessageConverterExtractor提取body(委托模式),然后将body和响应头、状态封装成ResponseEntity对象。

6.4.2提取响应body

提取分三步:

(1)提取器HttpMessageConverterExtractor寻找可用的转化器

在默认的RestTemplate的构造函数中初始化了转化器集合,包括:

转化器

可转化的类型 ByteArrayHttpMessageConverter byte[] StringHttpMessageConverter String ResourceHttpMessageConverter Resource SourceHttpMessageConverter javax.xml.transform.* AllEncompassingFormHttpMessageConverter MultiValueMap Jaxb2RootElementHttpMessageConverter XmlRootElement,XmlType(注解) ... MappingJackson2HttpMessageConverter Json

除了前五个,其他的转化器会由classloader尝试加载某个类来判断工程是否包含某个包,而后决定是否加入转化器集合。

提取器遍历转化器集合以查找可用的转化器,其中MappingJackson2HttpMessageConverter总是在最后一个,因为该类实现了GenericHttpMessageConverter,算是一个通用转化器,只有在找不到合适的转化器时才轮到它。Spring提供了一个该类的实现,以保证总是能得到该类。

(2)转化器寻找可用的反序列化器

转化器持有一个反序列化器缓存集合,首先从缓存中寻找

如果已有可用的反序列化器,则直接返回。否则创建一个新的反序列化器。

反序列化器保存着待反序列化类的域、方法、构造器等信息,反序列化时就是使用构造器创建了一个新的实例。

以jackson为例,创建反序列化器的过程在jackson-databind-xxx.jar中,有兴趣的可以看一下。调用栈如下(由下往上找):

BeanDeserializerFactory.addBeanProps/addObjectIdReader/addReferenceProperties/addInjectables

BeanDeserializerFactory.buildBeanDeserializer

BeanDeserializerFactory.createBeanDeserializer

(3)反序列化器执行反序列化

TOKEN

Json的一个或一组字符 START_OBJECT { END_OBJECT } START_ARRAY [ END_ARRAY ] VALUE_TRUE true VALUE_FALSE false ...

调用栈:

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文内容总结:1、什么是REST?,2、REST成熟度的四个层次,3、HTTP请求的方法,,4、HTTP请求的状态码,5、RestTemplate,5.1简介,5.2对外开放的接口,(2)每一个小类又分三种,这三种有什么区别?,(3)Exchange,(4)excute,6.doExcute,

原文链接:https://www.cnblogs.com/caolei1108/p/6169950.html