REST 客户端——细读RestTemplate

使用Spring MVC创建REST API

四、REST 客户端——细读RestTemplate

RestTemplate概述

spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。

在Spring应用程序中访问第三方REST服务与使用Spring RestTemplate类有关。

RestTemplate类的设计原则与许多其他Spring *模板类(例如JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。

RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。

根据源码结构

RestTemplate类中定义了大约四十个与 REST 资源交互的方法,其中大多数都对应于HTTP的方法。但是仔细分析,里面只有十二种方法。其余都是这12种方法的重载形式。下表描述了RestTemplate的12个独立方法。

序号 方法 重载方法数 描述
1 delete() 3 在特定的 URL 上对资源执行 HTTP DELETE 操作
2 exchange() 8 在 URL上执行特定的 HTTP 方法,返回包含对象的 ResponseEntity,这个对象是在响应体中映射得到的
3 excute() 3 在 URL上执行特定的 HTTP 方法,返回从响应体中映射得到的对象
4 getForObject() 3 发送一个 HTTP GET请求,返回的 请求体将映射成一个对象
5 getForEntity() 3 发送一个 HTTP GET请求,返回的 ResponseEntity包含了响应体所映射成的对象
6 HeadForHeaders() 3 发送一个 HTTP HEAD请求,返回包含特定资源URL的HTTP头
7 optionsForAllow() 3 发送一个 HTTP OPTIONS请求,返回对特定URL的Allow头信息
8 postForObject() 3 POST数据到一个URL,返回根据响应体匹配形成的对象
9 postForEntity() 3 POST数据到一个URL,返回包含一个对象的ResponseEntiry,这个对象是从响应体中映射得到的
10 postForLocation() 3 POST数据到一个URL,返回新创建资源的URL
11 put() 3 PUT资源到一个URL
12 patchForObject() 3 PATCH数据到一个URL,返回根据响应体匹配形成的对象

简单分析源码可以看出以下几个特点

  1. 除了TRACE意外,RestTemplate涵盖了所有的HTTP动作。除此之外,exchange()和excute()提供了较低层次的通用方法来使用任意的HTP方法,特定的方法其实最后都是走的excete()方法;

  2. 大多数操作都是以三种方式进行了重载:

  • 使用java.net.URI作为URL的形式,不支持参数化URI;
  • 使用String作为URL格式,并使用Map指明URL参数;
  • 使用Strig作为URL格式,并使用可变擦书列表指明URL参数。
  1. RestTemplate包含以下几个部分:
    • HttpMessageConverter 对象转换器
    • ClientHttpRequestFactory 默认是JDK的HttpURLConnection
    • ResponseErrorHandler 异常处理
    • ClientHttpRequestInterceptor 请求拦截器
  2. api位于org.springframework.web.client包下
  3. xxForObject()与xxForEntity()方法区别与联系
    1. 返回类型不同,xxForObject直接返回匹配的,而xxForEntity()方法返回一个ResponseEntity对象。该对象的body里存着映射成的对象,除此之外还有本次响应相关的额外信息,如状态码、HttpHeader信息等。
    2. 参数类型是一致的

RestTemplate官方 最新 API

使用示例

Get

源码接口:

<T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;

<T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

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

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

<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;
  1. 简单查询,uri里不带参数

    public static void testGet1() {
        final String uri = "http://localhost:8080/students";
    
        RestTemplate restTemplate = new RestTemplate();
        String object = restTemplate.getForObject(uri, String.class);
    
        System.out.println(object);
    }
  2. url参数

    public static void testGet2() {
        String uri = "http://localost:8080/student/{studentId}";
        RestTemplate restTemplate = new RestTemplate();
    
        int studentId = 1;
    
        Student student = restTemplate.getForObject(uri, Student.class, studentId);
        System.out.println(student);
    }
    public static void testGet3() {
        String uri = "http://localost:8080/student/{studentId}";
        RestTemplate restTemplate = new RestTemplate();
    
        int studentId = 1;
        Map<String, Integer> params = new HashMap<String, Integer>();
        params.put("studentId", studentId);
    
        Student student = restTemplate.getForObject(uri, Student.class, params);
        System.out.println(student);
    }
  3. 如果GET方法请求参数需要添加认证、Header头信息等,则需要使用exchange()方法,见下文。

Post

Put

Patch

Options

Delete

exchange()

上文中提到,xxForObject()方法与xxForEntity()方法的区别是后者可以同时返回对象和响应头、状态码。能在响应中读取到这头信息是很有用的。但是如果想在发送给服务器的请求中设置头信息的话,怎么办呢?这就是RestTemplate的exchange()的用武之地。

exchange()的 8 个接口 源码:

<T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
            Class<T> responseType, Object... uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
            Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(URI url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
            Class<T> responseType) throws RestClientException;

<T> ResponseEntity<T> exchange(String url,HttpMethod method, @Nullable HttpEntity<?> requestEntity,
            ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
            ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(URI url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
            ParameterizedTypeReference<T> responseType) throws RestClientException;

<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType)
            throws RestClientException;

<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
            throws RestClientException;

exchange()方法使用HttpMethod参数来表明要使用的HTTP动作。根据此参数,该方法可以与上文具体的HTTP方法一样的工作。

public void testGet4() {
    HttpHeaders headers = new HttpHeaders();
    headers.set("kbn-xsrf", "true");
    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

    // 手动添加认证
    String userName = "root";
    String password = "123456";
    String str = userName + ":" + password;
    String auth = "Basic " + Base64GeneratorUtil.str2Base64(str);
    headers.set("Authorization", auth);

    // 如果需要 还可以在这里添加一些json字符串信息
    String jsonObj = "{}";
    HttpEntity<String> request = new HttpEntity<>(jsonObj, headers);

    String uri = "http://localost:8080/student/{studentId}";

    RestTemplate restTemplate = new RestTemplate();
    int studentId = 1;
    ResponseEntity<Student> entity = restTemplate.exchange(uri, HttpMethod.PUT, request, Student.class, studentId);
    Student student = entity.getBody();
    HttpStatus statusCode = entity.getStatusCode();
    HttpHeaders headers1 = entity.getHeaders();
}

excute()

略。

上一篇:springboot项目下载文件功能中-切面-导致的下载文件失败的bug


下一篇:高效开发:Mybatis中useGeneratedKeys的用法