【Spring Cloud系列】- RestTemplate使用详解(下)

简介: 【Spring Cloud系列】- RestTemplate使用详解(下)

2.6. 执行requestCallback.doWithRequest(request);

RequestCallback 封装了请求体和请求头对象,既在RequstCallback可以输入需要传输的head数据

在执行 doWithRequest 时,与Connection发送请求体有着密切关系,请求头就是 SimpleBufferingClientHttpRequest.addHeaders 方法,那么请求体 bufferedOutput 是如何赋值的呢?就是在 doWithRequest 里面,如下 StringHttpMessageConverter (其他 MessageConvert 也一样,这里也是经常乱码的原因;

RequestCallback 用于操作请求头和body,在请求发出前执行。以下是RequestCallback的 两个实现类

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

2.7. 接着执行 response = request.execute();

调用接口ClientHttpRequest

public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {
    ClientHttpResponse execute() throws IOException;
}

然后使用实例 SimpleBufferingClientHttpRequest 封装请求体和请求头

@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
  addHeaders(this.connection, headers);
  // JDK <1.8 doesn't support getOutputStream with HTTP DELETE
  if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
      this.connection.setDoOutput(false);
  }
  if (this.connection.getDoOutput() && this.outputStreaming) {
    this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
  }
  this.connection.connect();
  if (this.connection.getDoOutput()) {
    FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
  }
  else {
    // Immediately trigger the request in a no-output scenario as well
    this.connection.getResponseCode();
  }
  return new SimpleClientHttpResponse(this.connection);
}

Delete通过请求方式和是否有请求体对象来判断是否需要发送请求体如果是delete请求,首先设置 DoOutput = true,然后根据是否有请求体数据,然后封装请求体FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());

2.8. 解析response

接着就是 response 的解析了,主要还是 Error 的解析。this.handleResponse(url, method, response);

内部处理多是解析error处理

protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
  ResponseErrorHandler errorHandler = getErrorHandler();
  boolean hasError = errorHandler.hasError(response);
  if (logger.isDebugEnabled()) {
     try {
        HttpStatusCode statusCode = response.getStatusCode();
        logger.debug("Response " + statusCode);
      }
      catch (IOException ex) {
        logger.debug("Failed to obtain response status code", ex);
      }
   }
   if (hasError) {
      errorHandler.handleError(url, method, response);
   }
}

三、RestTemplate常用方法及示例

3.1. RestTemplate中Get方法使用

3.1.1 getForObject(URI url, Class responseType)
@Test
public void TestRestGetMethod() throws Exception {
    RestTemplate restTemplate = new RestTemplate();
    URI url = URI.create("http://api.goyeer.com:8888/user");
    String response = restTemplate.getForObject(url, String.class);
}
3.1.2 getForObject(String url, Class responseType, Object… uriVariables)
@Test
public void TestGetForObjcetByArgument() throws Exception {
    RestTemplate restTemplate = new RestTemplate();
    String appkey="Goy_20200034_MES";
    String appSecret="GY202305-0801-41d4-a716-9998880";
    String url = "http://api.goyeer.com:8888/getToken?appkey={1}&appsecret={2}";
    String responseToken = restTemplate.getForObject(url,String.class, appkey,appSecret);
}
3.1.3 getForObject(String url, Class responseType, Map<String, ?> uriVariables)
@Test
public void TestGetForObjectByMap() throws Exception{
    Map<String,Object> map=new HashMap();
    map.put("appkey","Goy_20200034_MES");
    map.put("appSecret","GY202305-0801-41d4-a716-9998880");
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://api.goyeer.com:8888/user?appkey={appkey}&appsecret={appSecret}";
    String response = restTemplate.getForObject(url,String.class, map);
}
3.1.4 ResponseEntity getForEntity(URI url, Class responseType)
@Test
public void TestGetForEntity() throws Exception {
    RestTemplate restTemplate = new RestTemplate();
    URI url = URI.create("http://api.goyeer.com:8888/user");
    ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
    int httpCode =response.getStatusCode().value();
    String resp= response.getBody();
    System.out.println(httpCode);
    System.out.println(resp);
}
3.1.5 ResponseEntity getForEntity(String url, Class responseType, Object… uriVariables)
@Test
public void TestGetForEntityByArgument() throws Exception {
    RestTemplate restTemplate = new RestTemplate();
    String appkey="Goy_20200034_MES";
    String appSecret="GY202305-0801-41d4-a716-9998880";
    String url = "http://api.goyeer.com:8888/getToken?appkey={1}&appsecret={2}";
    ResponseEntity<String> response  = restTemplate.getForEntity(url,String.class, appkey,appSecret);
    int httpCode =response.getStatusCode().value();
    String resp= response.getBody();
    System.out.println(httpCode);
    System.out.println(resp);
}
3.1.6 getForEntity(String url, Class responseType, Map<String, ?> uriVariables)
@Tes
public void TestGetForEntityByMap() throws Exception {
    RestTemplate restTemplate = new RestTemplate();
    Map<String,Object> map=new HashMap();
    map.put("appkey","Goy_20200034_MES");
    map.put("appSecret","GY202305-0801-41d4-a716-9998880");
    String url = "http://api.goyeer.com:8888/getToken?appkey={appkey}&appsecret={appsecret}";
    ResponseEntity<String> response  = restTemplate.getForEntity(url,String.class, map);
    int httpCode =response.getStatusCode().value();
    String resp= response.getBody();
    System.out.println(httpCode);
    System.out.println(resp);
}

3.1.7 getForEntity与getForObject区别

GetForEntity和GetForObject用法几乎完全一致,区别在于前者可以查看请求状态码,请求头信息。

getForEntity返回的是一个ResponseEntity,而getForObject返回的就只是返回内容。getForObject的返回相当于只返回http的body部份而getForEntity的返回是返回全部信息

3.2. RestTemplate中POST方法使用

3.2.1. postForObject(URI url, @Nullable Object request, Class responseType)
@Test
public void TestPostForObject() {
  try {
         RestTemplate restTemplate = new RestTemplate();
         URI url = URI.create("http://api.goyeer.com:7777/user/create");
         User user = new User();
         user.setId(1110L);
         user.setLoginName("Goy");
         user.setDepartment("Department");
         User respUser = restTemplate.postForObject(url, user, User.class);
         System.out.println(respUser.getLoginName());
   } catch (Exception exception) {
        throw exception;
   }
}
3.2.2. postForObject(String url, @Nullable Object request, Class responseType, Object… uriVariables)
@Test
public void TestPostForObejectByArgument()throws Exception{
    RestTemplate restTemplate = new RestTemplate();
    try {
        String uri="http://api.goyeer.com:7777/{1}/{2}";
        String controllerName="user";
        String operateName="create";
        User user = new User();
        user.setId(1110L);
        user.setLoginName("Goy");
        user.setDepartment("Department");
        User respUser = restTemplate.postForObject(uri, user, User.class,controllerName,operateName);
        System.out.println(respUser.getLoginName());
    } catch (Exception e) {
        throw new RuntimeException(e);
3.2.3. postForObject(String url, @Nullable Object request, Class responseType,Map<String, ?> uriVariables)
@Test
public void TestPostForObjectByMap() {
   RestTemplate restTemplate = new RestTemplate();
   try {
      String uri="http://localhost:7777/{controller}/{operate}";
      Map map=new HashMap();
      map.put("controller","user");
      map.put("operate","create");
      User user = new User();
      user.setId(1110L);
      user.setLoginName("Goy");
      user.setDepartment("Department");
      User respUser = restTemplate.postForObject(uri, user, User.class,map);
      System.out.println(respUser.getLoginName());
    } catch (Exception e) {
       throw new RuntimeException(e);
    }
}
3.2.4. 其他常用POST的方法

其它提供POST的方法有postForLocationpostForEntity用法如postForObject

相比于postForObject()方法, postForEntity() 返回响应体为 ResponseEntity 类型,其他两个方法功能一致。

与postForObject 和 postForEntity 方法类型, postForLocation 也发送post请求至特定uri并创建新的对象。唯一的差异是返回值为Location头信息。

四、常用RestTemplate方法

4.1. Head请求使用headForHeaders方法

headForHeaders方法 是HTTP中请求的一种。HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。一个HEAD请求的响应中,HTTP头中包含的元信息应该和一个GET请求的响应消息相同。这种方法可以用来获取请求中隐含的元信息,而不用传输实体本身。也经常用来测试超链接的有效性、可用性和最近的修改。

一个HEAD请求的响应可被缓存,也就是说,响应中的信息可能用来更新之前缓存的实体。如果当前实体跟缓存实体的阈值不同(可通过Content-Length、Content-MD5、ETag或Last-Modified的变化来表明),那么这个缓存就被视为过期了。

  • headForHeaders(String url, Object… uriVariables)
  • headForHeaders(String url, Map<String, ?> uriVariables)
  • headForHeaders(URI url)

以上三个方法使用方法同getForObject类似

4.2. Put请求使用put方法

PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。

  • put(String url, @Nullable Object request, Object… uriVariables)
  • put(String url, @Nullable Object request, Map<String, ?> uriVariables)
  • put(URI url, @Nullable Object request)

以上三个方法使用方法同getForObject类似

4.2. PATCH请求使用patchForObject方法

HTTP中为了提高交互操作性与防止错误,确实需要一种新的修改方法,而PUT方法已经被定义为用一个请求体去修改一个完整的资源。并且不能重复做部分更改,否则代理和缓存、甚至服务器或者客户端都会得到有问题的操作结果。

至此,PATCH方法有了被完全定义的必要。

PATCH在请求中定义了一个描述修改的实体集合,如果被请求修改的资源不存在,服务器可能会创建一个新的资源。

  • patchForObject(URI url, @Nullable Object request, Class responseType)
  • patchForObject(String url, @Nullable Object request, Class responseType,Map<String, ?> uriVariables)
  • patchForObject(String url, @Nullable Object request, Class responseType,Object… uriVariables)

以上三个方法使用方法同getForObject类似

4.2. Delete请求使用patchForObject方法

向服务器端提交数据,请求数据在报文body里;发送一个删除数据的请求。

  • delete(String url, Object… uriVariables)
  • delete(String url, Map<String, ?> uriVariables)
  • delete(URI url)

以上三个方法使用方法同getForObject类似

五、总结

RestTemplate是Spring自带的一个调用rest服务的客户端,它提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。在一般项目中完全可以替代HttpClient和OkHttp。

在后续Spring cloud系列文章中会多次使用到。



目录
相关文章
|
16小时前
|
监控 安全 Java
Spring cloud原理详解
Spring cloud原理详解
7 0
|
4天前
|
消息中间件 负载均衡 Java
【Spring Cloud 初探幽】
【Spring Cloud 初探幽】
13 1
|
6天前
|
Java 开发者 微服务
Spring Cloud原理详解
【5月更文挑战第4天】Spring Cloud是Spring生态系统中的微服务框架,包含配置管理、服务发现、断路器、API网关等工具,简化分布式系统开发。核心组件如Eureka(服务发现)、Config Server(配置中心)、Ribbon(负载均衡)、Hystrix(断路器)、Zuul(API网关)等。本文讨论了Spring Cloud的基本概念、核心组件、常见问题及解决策略,并提供代码示例,帮助开发者更好地理解和实践微服务架构。此外,还涵盖了服务通信方式、安全性、性能优化、自动化部署、服务网格和无服务器架构的融合等话题,揭示了微服务架构的未来趋势。
31 6
|
10天前
|
JSON Java Apache
Spring Cloud Feign 使用Apache的HTTP Client替换Feign原生httpclient
Spring Cloud Feign 使用Apache的HTTP Client替换Feign原生httpclient
|
11天前
|
负载均衡 Java 开发者
Spring Cloud:一文读懂其原理与架构
Spring Cloud 是一套微服务解决方案,它整合了Netflix公司的多个开源框架,简化了分布式系统开发。Spring Cloud 提供了服务注册与发现、配置中心、消息总线、负载均衡、熔断机制等工具,让开发者可以快速地构建一些常见的微服务架构。
|
12天前
|
消息中间件 Java RocketMQ
Spring Cloud RocketMQ:构建可靠消息驱动的微服务架构
【4月更文挑战第28天】消息队列在微服务架构中扮演着至关重要的角色,能够实现服务之间的解耦、异步通信以及数据分发。Spring Cloud RocketMQ作为Apache RocketMQ的Spring Cloud集成,为微服务架构提供了可靠的消息传输机制。
27 1
|
12天前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo: 微服务通信的高效解决方案
【4月更文挑战第28天】在微服务架构的发展中,服务间的高效通信至关重要。Spring Cloud Dubbo 提供了一种基于 RPC 的通信方式,使得服务间的调用就像本地方法调用一样简单。本篇博客将探讨 Spring Cloud Dubbo 的核心概念,并通过具体实例展示其在项目中的实战应用。
15 2
|
12天前
|
监控 Java Sentinel
Spring Cloud Sentinel:概念与实战应用
【4月更文挑战第28天】在分布式微服务架构中,确保系统的稳定性和可靠性至关重要。Spring Cloud Sentinel 为微服务提供流量控制、熔断降级和系统负载保护,有效预防服务雪崩。本篇博客深入探讨 Spring Cloud Sentinel 的核心概念,并通过实际案例展示其在项目中的应用。
23 0
|
12天前
|
Cloud Native Java Nacos
Spring Cloud Nacos:概念与实战应用
【4月更文挑战第28天】Spring Cloud Nacos 是一个基于 Spring Cloud 构建的服务发现和配置管理工具,适用于微服务架构。Nacos 提供了动态服务发现、服务配置、服务元数据及流量管理等功能,帮助开发者构建云原生应用。
20 0