RestTemplate的介绍

版权声明:转载请付原创连接 https://blog.csdn.net/qq_20957669/article/details/87910905

简介

Spring RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端使用

RestTemplate定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。 
其实,这里面只有11个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了36个方法。

delete() 在特定的URL上对资源执行HTTP DELETE操作

exchange() 在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中 
映射得到的

execute() 在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象

getForEntity() 发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象

getForObject() 发送一个HTTP GET请求,返回的请求体将映射为一个对象

postForEntity()  POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得 
到的

postForObject() POST 数据到一个URL,返回根据响应体匹配形成的对象

headForHeaders() 发送HTTP HEAD请求,返回包含特定资源URL的HTTP头

optionsForAllow() 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息

postForLocation() POST 数据到一个URL,返回新创建资源的URL

put() PUT 资源到特定的URL

1.1名词释义

  • RestTemplate:REST模板
  • exchange:交换
  • Entity:实体

RestTemplate有两个构造方法,分别是:

public RestTemplate() {
          /**
               ...初始化过程
          */
}
 
public RestTemplate(ClientHttpRequestFactory requestFactory) {
     this();
     setRequestFactory(requestFactory);
}

第一个构造方法,我们无法控制超时时间

第二个构造中的ClientHttpRequestFactory接口的实现类中存在timeout属性,因此选用第二个构造方法。 ClientHttpRequestFactory 指定不同的HTTP请求方式。默认使用 SimpleClientHttpRequestFactory,是 ClientHttpRequestFactory 实现类

  • 使用配置方式

1.可以在spring配置文件xml中进行如下配置:

<!-- 配置RestTemplate -->
         <!--Http client Factory-->  
        <bean id="httpClientFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory">  
            <property name="connectTimeout"  value="${connectTimeout}"/>
            <property name="readTimeout"  value="${readTimeout}"/>
        </bean>  
           
        <!--RestTemplate-->  
        <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">  
            <constructor-arg ref="httpClientFactory"/>  
        </bean>

2.也可以直接使用:

        SimpleClientHttpRequestFactory requestFactory = 
        new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(1000);
        requestFactory.setReadTimeout(1000);
        RestTemplate restTemplate = new RestTemplate(requestFactory);

注意:ClientHttpRequestFactory 接口有4个实现类,分别是:

  • AbstractClientHttpRequestFactoryWrapper 用来装配其他request factory的抽象类。
  • CommonsClientHttpRequestFactory 允许用户配置带有认证和http连接池的httpclient,已废弃,推荐用HttpComponentsClientHttpRequestFactory。
  • HttpComponentsClientHttpRequestFactory 同2.
  • SimpleClientHttpRequestFactory 接口的一个简单实现,可配置proxy,connectTimeout,readTimeout等参数。
  • GET

GET请求有两种方式:getForObject 和 getForEntity,那么这两种有什么区别?

  • 从接口的签名上,可以看出一个是直接返回预期的对象,一个则是将对象包装到 ResponseEntity 封装类中
  • 如果只关心返回结果,那么直接用 GetForObject 即可
  • 如果除了返回的实体内容之外,还需要获取返回的header等信息,则可以使用 getForEntity

 a.getForObject方式

Spring的RestTemplate提供了许多的支持,这里仅仅列出常用的接口:

   public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException 
   public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables) throws RestClientException
   public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException

使用示例:

 // 使用方法一,不带参数
	 String url = "https://story.hhui.top/detail?id=666106231640";
	 InnerRes res = restTemplate.getForObject(url, InnerRes.class);
	 System.out.println(res);
	 //	或
	 java String message = 
	 restTemplate.getForObject("http://localhost:8080/yongbarservice/appstore/appgoods/re
	 stTemplate?name=zhaoshijie&id=80", String.class );
	 
	 // 使用方法一,传参替换
	 url = "https://story.hhui.top/detail?id={?}";
	 res = restTemplate.getForObject(url, InnerRes.class, "666106231640");
	 System.out.println(res);
	 // 或
	 String result = 
	 restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", 
	 String.class,"42", "21");
	 
	 // 使用方法二,map传参
	 url = "https://story.hhui.top/detail?id={id}";
	 Map<String, Object> params = new HashMap<>();
	 params.put("id", 666106231640L);
	 res = restTemplate.getForObject(url, InnerRes.class, params);
	 System.out.println(res);
	 // 或
	 Map<String, String> vars = Collections.singletonMap("hotel", "42");
	 String result = 
	 restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", 
	 String.class, vars);
	 // 使用方法三,URI访问
	 URI uri = URI.create("https://story.hhui.top/detail?id=666106231640");
	 res = restTemplate.getForObject(uri, InnerRes.class);
	 System.out.println(res);

主要看一下getForObject(java.lang.String, java.lang.Class<T>, java.lang.Object...) 的使用姿势

  • 根据实际传参替换url模板中的内容
  • 使用方法一时,模板中使用 {?} 来代表坑位,根据实际的传参顺序来填充
  • 使用方法二时,模板中使用 {xx}, 而这个xx,对应的就是map中的key

b.getForEntity方式

getForEntity理论上也应该有对应的三种方式

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException ;
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;

使用示例; 

String url = "https://story.hhui.top/detail?id=666106231640";
 ResponseEntity<InnerRes> res = restTemplate.getForEntity(url, InnerRes.class);
 System.out.println(res);

我们主要关注的就是ResponseEntity封装中,多了哪些东西,截图如下

从上面可以看出,多了两个东西

  • 一个返回的http状态码,如200表示请求成功,500服务器错误,404not found等
  • 一个 ResponseHeader
  • POST

post请求除了有forObject 和 forEntity之外,还多了个forLocation;其次post与get一个明显的区别就是传参的姿势问题,get的参数一般会待在url上;post的则更常见的是通过表单的方式提交

a.postForObject方法

Spring的RestTemplate对post的常用接口:

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

public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException

public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException

常用的方法为:

@Test
public void testPost() {
 String url = "http://localhost:8080/post";
 String email = "[email protected]";
 String nick = "一灰灰Blog";
 
 MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
 request.add("email", email);
 request.add("nick", nick);
 
 // 使用方法一
 ans = restTemplate.postForObject(url, request, String.class);
 System.out.println(ans);
 
 // 使用方法一,但是结合表单参数和uri参数的方式,其中uri参数的填充和get请求一致
 request.clear();
 request.add("email", email);
 ans = restTemplate.postForObject(url + "?nick={?}", request, String.class, nick);
 System.out.println(ans);
 
 
 // 使用方法二
 Map<String, String> params = new HashMap<>();
 params.put("nick", nick);
 ans = restTemplate.postForObject(url + "?nick={nick}", request, String.class, params);
 System.out.println(ans);

 // 使用方法三
 URI uri = URI.create(url);
 String ans = restTemplate.postForObject(uri, request, String.class);
 System.out.println(ans);
 
}

上面分别给出了三种方法的调用方式,其中post传参区分为两种,一个是uri参数即拼接在url中的,还有一个就是表单参数 

  • uri参数,使用姿势和get请求中一样,填充uri中模板坑位
  • 表单参数,由MultiValueMap封装,同样是kv结构

b.postForEntity

和前面的使用姿势一样,无非是多了一层包装而已

c.postForLocation

提供了三个接口,分别如下,需要注意的是返回结果,为URI对象,即网络资源

使用场景:一般登录、注册都是post请求,而这些操作完成之后呢?大部分都是跳转到别的页面去了,这种场景下,就可以使用 postForLocation 了,提交数据,并获取返回的URI,一个测试如下


 public URI postForLocation(String url, @Nullable Object request, Object... uriVariables)
 throws RestClientException ;
 
public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
 throws RestClientException ;
 
public URI postForLocation(URI url, @Nullable Object request) throws RestClientException ;
 

首先mock一个后端接口:

@ResponseBody
@RequestMapping(path = "success")
public String loginSuccess(String email, String nick) {
 return "welcome " + nick;
}
 
@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST})
public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email,
  @RequestParam(value = "nick", required = false) String nick) {
 return "redirect:/success?email=" + email + "&nick=" + nick + "&status=success";
}
 

访问的测试用例:

@Test
public void testPostLocation() {
 String url = "http://localhost:8080/post";
 String email = "[email protected]";
 String nick = "一灰灰Blog";
 
 MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
 request.add("email", email);
 request.add("nick", nick);
 
 // 使用方法三
 URI uri = restTemplate.postForLocation(url, request);
 System.out.println(uri);
}
  • PUT方式:

restTemplate.put("http://localhost:8080/yongbarservice/appstore/appgoods/restTemplate?name=zhaoshijie&id=80" ,null); 
  • DELETE方式

//delete方法(注意:delete方法没有返回值,说明,id=0这个参数在服务器端可以不定义该参数,直接使用request获取) 
// restTemplate.delete("http://localhost:8080/yongbarservice/appstore/appgoods/deleteranking?id=0"); 

小结

上面目前只给出了Get/Post两种请求方式的基本使用方式,并没有涉及到更高级的如添加请求头,添加证书,设置代理等,高级的使用篇等待下一篇出炉,下面小结一下上面的使用姿势

1. Get请求

get请求中,参数一般都是带在url上,对于参数的填充,有两种方式,思路一致都是根据实际的参数来填充url中的占位符的内容;根据返回结果,也有两种方式,一个是只关心返回对象,另一个则包含了返回headers信心
参数填充

1、形如  http://story.hhui.top?id={0} 的 url

  • 调用 getForObject(String url, Class<T> responseType, Object... uriVariables)
  • 模板中的0,表示 uriVariables 数组中的第0个, i,则表示第i个
  • 如果没有url参数,也推荐用这个方法,不传uriVariables即可

2、形如  http://story.hhui.top?id={id} 的 url

  • 调用 getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
  • map参数中的key,就是url参数中 {} 中的内容

其实还有一种传参方式,就是path参数,填充方式和上面一样,并没有什么特殊的玩法,上面没有特别列出

返回结果

  • 直接获取返回的数据  getForObject
  • 获取待responseHeader的数据 getForEntity

2. Post请求

  • post请求的返回也有两种,和上面一样
  • post请求,参数可以区分为表单提交和url参数,其中url参数和前面的逻辑一致
  • post表单参数,请包装在 MultiValueMap 中,作为第二个参数 Request 来提交
  • post的方法,还有一个 postForLocation,返回的是一个URI对象,即适用于返回网络资源的请求方式

3. 其他

最前面提了多点关于网络请求的常见case,但是上面的介绍,明显只处于基础篇,我们还需要关注的有

  • 如何设置请求头?
  • 有身份验证的请求,如何携带身份信息?
  • 代理的设置
  • 文件上传可以怎么做?
  • post提交json串(即RequestBody) 又可以怎么处理

上面可能还停留在应用篇,对于源码和实现有兴趣的话,问题也就来了

  • RestTemplaet的实现原理是怎样的
  • 前面url参数的填充逻辑实现是否优雅
  • 返回的对象如何解析
  • ....

参考:https://www.jb51.net/article/145618.htm

https://blog.csdn.net/itguangit/article/details/78825505 

猜你喜欢

转载自blog.csdn.net/qq_20957669/article/details/87910905