RestTemplate入门

696 阅读6分钟

RestTemplate

1、简介

RestTemplate是spring3.0开始支持的一个同步的web http请求工具,Spring框架进行了抽象,提供了常见的REST请求方案的模板,例如GET、POST、PUT、DELETE请求及一些通用的请求执行方法。RestTemplate实现了RestOperations接口,并定义了基本的RESTful操作。

传统情况下,可以使用Java自带的HttpUrlConnection或者HttpClient也可以实现RESTful服务访问。

2、常见http客户端请求工具

  • HttpURLConnection
  • HttpClient
  • okHttp

3、http状态码

状态码描述
1XX 信息提示,代表临时的响应
100-Continue初始的请求已经接受,客户应继续发送请求的其余部分(http1.1)
101-Switching Protocols服务器将遵从客户的请求转换到另一种协议(http1.1)
2XX 成功
200-OKhttp请求成功
201-Created服务器已经创建的文档
202-Accepted服务器接受请求,但处理尚未完成
3XX 重定向
300-MultipleChoices客户端请求的文档可在多个位置找到
301-Move Permanently永久移动,请求的资源已经被永久的移动到新的url
302-Found临时移动
303-See Other查看其他地址
304-Not Modified未修改,所请求的资源未修改
4XX 客户端错误
4000-Bad Request请求出现语法错误
401-Unauthorized请求要求用户的身份认证
402-Payment Required保留,将来使用
403-Forbidden拒绝执行
404-Not Found服务器无法找到请求的资源
5XX 服务器错误
500-Internet Server Error服务器内部错误
501-Not Implemented服务器不支持请求的功能
502-Bad GateWay网关请求错误
503-Service Unavailable服务部可用

这里只列出常用的http状态响应码,更多详细内容参见:www.runoob.com/http/http-s…

4、RestTemplate方法

HTTP方法RESTTEMPLATE方法
DELETEdelete:在特定的url上执行delete操作
GETgetForObject:发送一个get请求,返回的请求映射为一个对象getForEntity:返回包含一个对象的ResponseEntity
HEADheadForHeaders:发送一个http head请求,发挥包含特定资源url的http头
OPTIONSoptionsForAllow:返回特定的url的allow头信息
POSTpostForLocation:返回新创建资源的urlpostForObject:post数据到特定的url,返回根据响应体匹配形成的对象postForEntity:返回一个包含对象的ResponseEntity,这个对象是响应体中映射得到
PUTput:普通资源到特定的url
任何exchange:返回包含对象的ResponseEntity,对象是从响应体中得到的execute:在url上执行特定的http方法,返回一个从响应体映射得到的对象

5、RestTemplate的使用

首先我们创建一个工程,resttemplate的基本配置,使用spring boot自动注解的方式。在调用rest时,每次请求都需要和服务端建立连接,为了避免多次建立连接的操作浪费资源,我们这里采用连接池的配置。

5.1.依赖

除了spring的基本依赖外,还需要在在maven的pom.xml中添加如下依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>${httpclient.version}</version>
</dependency>

5.2.使用示例

创建resttemplate配置类:

package com.crystal.master.rest;

import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class RestConfig {

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate(clientHttpRequestFactory());
}

@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
    return new HttpComponentsClientHttpRequestFactory(httpClient());
}

@Bean
public HttpClient httpClient() {
    // 配置http连接
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
    // 配置连接池最大连接数
    poolingHttpClientConnectionManager.setMaxTotal(50);
    // 最大同路由并发数
    poolingHttpClientConnectionManager.setDefaultMaxPerRoute(500);

    // requestConfig
    RequestConfig requestConfig = RequestConfig.custom()
            // 服务器返回数据的时间
            .setSocketTimeout(10000)
            // 连接服务器(握手成功)的时间,超出时间抛出异常
            .setConnectTimeout(5000)
            // 连接池获取连接的时间
            .setConnectionRequestTimeout(500)
            .build();
    // 设置请求头
    List<Header> headers = new ArrayList();
    headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
    headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
    headers.add(new BasicHeader("Accept-Language", "zh-CN"));
    headers.add(new BasicHeader("Connection", "keep-alive"));
    headers.add(new BasicHeader("Content-type", "application/json,charset=UTF-8"));

    return HttpClientBuilder.create()
            .setDefaultRequestConfig(requestConfig)
            .setConnectionManager(poolingHttpClientConnectionManager)
            .setDefaultHeaders(headers)
            // 保持长连接,需要在头添加keep-alive
            .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
            // 开始重试
            .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
            .build();
}

}

5.3.GET请求

做好配置工作后,先来看下使用RestTemplate发送get请求,get请求相关的主要方法有getForObject和getForEntity。下面我们分别模拟使用

getForEntity: resttemplate发送的http请求,那么响应的数据中必然也存在响应头,如果开发者需要获取响应头信息的话,那么需要使用getForEntity,此时返回的是ResponseEntity的实例。

在创建的好的工程中,创建一个RestTemplateController,在RestTemplateController中创建getForEntity方法,如下:

package com.crystal.master.controller;

import com.crystal.common.dto.UserDTO;
import io.swagger.annotations.Api;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@Api(value = "restful")
@RestController
@RequestMapping("/rest")
public class RestTemplateController {
    @Resource
    @Lazy
    private RestTemplate restTemplate;

    @RequestMapping(value = "/getForEntity", method = { RequestMethod.GET })
    public UserDTO getForEntity() {
        ResponseEntity<UserDTO> responseEntity = restTemplate.getForEntity("http://localhost:8080/welcome/hello", UserDTO.class);
        return responseEntity.getBody();
    }
}

启动项目,在浏览器中输入http://localshot:8080/rest/getForEntity,在return resonseEntity.getBody()处设置断点,看到如下信息:

image-20211204163608390.png

继续执行,可以看到浏览器返回结果:

image-20211204163720449.png

5.4.POST请求

和get方法相比,post请求的方法除了postForEntity和postForObject外,还有一个postForLocation.

postForEntity: 在post请求中,参数的传递可以是key/value形式,也可以是json格式。 @RequestMapping(value = "/postForEntity", method = { RequestMethod.GET }) public String postForEntity(String name) { MultiValueMap map = new LinkedMultiValueMap<>(); map.add("name", name); ResponseEntity responseEntity = restTemplate.postForEntity("http://localhost:8080/welcome/postForEntity", map, String.class); return responseEntity.getBody(); }

创建一个UserController来测试。

@RequestMapping(value = "/postForEntity", method = { RequestMethod.POST })
public String postForEntity(String name) {
    return "hello, " + name;
}

json格式:在公共common项目中新建一个UserDTO对象,这里只需把传来的userdto对象返回回去即可。

@RequestMapping(value = "/postForEntityJson", method = { RequestMethod.GET })
public UserDTO postForEntityJson() {
    UserDTO userDTO = new UserDTO();
    userDTO.setUserName("crystal");
    userDTO.setAge(18);
    ResponseEntity<UserDTO> responseEntity = restTemplate.postForEntity("http://localhost:8080/welcome/postForEntityJson", userDTO, UserDTO.class);
    return responseEntity.getBody();
}

在UserController中新建一个接收参数为userDTO的方法测试postForEntity方法。

@RequestMapping(value = "/postForEntityJson", method = { RequestMethod.POST })
public UserDTO postForEntityJson(@RequestBody UserDTO userDTO) {
    return userDTO;
}

postForObject: 和postForEntity基本一致,返回类型不同,这里不在赘述。

5.5.exchange

RestTemplate的一个通用的方法,这个方法需要在调用的时候指定请求类型,既能做get请求,也可以做post请求,或者其他请求类型(HttpMethod枚举类)。

 @RequestMapping(value = "/exchange", method = { RequestMethod.GET })
    public String exchange() {
        // 使用exchange时可以指定请求头
        HttpHeaders headers = new HttpHeaders();
        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(null, headers);
        ResponseEntity<String> responseEntity = restTemplate.exchange("http://localhost:8080/welcome/hello", HttpMethod.GET, null, String.class);
        return responseEntity.getBody();
    }

这里的参数和get和post中的差不多,注意参数中多了个请求类型的参数HttpMethod.GET,其中HttpEntity创建时需要传递两个参数,示例中我们第一个参数设置了null,这个参数相当于post中的第二个参数。HttpEntity中第二个参数就是请求头了,可以根据自己实际情况指定请求头。

5.6.execute

查看源码可知,所有的get、post、delete等方法最终都是调用的execute方法。

  • public T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor responesExtractor, Object ... uriVariables)
    @Nullable
    public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
        URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
        return this.doExecute(expanded, method, requestCallback, responseExtractor);
    }
    
  • public T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor responesExtractor, Map(<String, ?> uriVariables)
    @Nullable
    public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables) throws RestClientException {
        URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
        return this.doExecute(expanded, method, requestCallback, responseExtractor);
    }
    
    从上面的源码可以看出,execute是将String格式的uri转换成java.net.URI,之后调用doExecute方法。

5.7.其他

RestTemplate中还有一些其他方法,put、delete、postForLocation 等方法,具体实际使用的方法我们就不在这里一一展示了,需要的可以查看RestTemplate自行学习。

总结:本篇主要介绍了RestTemplate这样一个http请求工具的基本方法,文中未涉及的其他一些方法,有兴趣的小伙伴可以自行查阅资料学习使用。在SpringMVC中支持良好的RESTful风格接口开发,RestTemplate在设计中,也提供了很好的RESTful请求封装,掌握这个基本工具的使用是必要的。