SpringBoot 2.x系列:RestTemplate

1,346 阅读5分钟

概览

上一篇介绍了如何使用Spring Boot构建RESTful风格Web服务的实现方法,juejin.cn/post/695494…,完成了Web服务构建后,大部分情况下将接口提供给前端的小伙伴去调用就可以了,实际开发过程中也会涉及到后端去调用另外一个后端写的接口,我们需要做的事情就是如何对服务进行消费,目前常用有三种方式

  • JDK自带的HttpConnection
  • Apache的HttpClient
  • Spring封装的RestTemplate

严格意思是RestTemplate底层并没有自己去实现Http协议栈,RestTemplate只是Spring定义一个模板,类似JDBCTemplate,底层实际发送Http请求还是通过HttpConnetion或者HttpClient,具体使用哪个类库,可以在自定义RestTemplate的时候来指定。当然相较传统的 HttpClient 客户端工具类库,RestTemplate 在编码的简便性以及异常的处理等方面都做了很多改进。

RestTemplate常用方法介绍

在远程访问上,RestTemplate内置了一批常用的工具方法,我们可以根据HTTP的语义以及RESTful的设计原则对这些方法进行归类:

HTTP方法RestTemplate方法组
GETgetForObject/getForEntity
POSTpostForLocation/postForObject/postForEntity
PUTput
DELETEdelete
HeaderheadForHeaders
不限Exchange/execute

好,常用方法介绍完后,接下来我们通过一个简单的入门,把这些方法实际走一边,注意:本节的入门Demo需要依赖上一节介绍构建RESTful Web服务提供的接口服务

简单入门

实例代码对应的仓库地址:

github.com/dragon8844/…

gitee.com/drag0n/spri…

引入依赖

在pom.xml的文件中引入相关依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
  
	<!--简化代码-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
  
	<!--使用httpclient实现http客户端-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
        </dependency>
  
        <!-- 方便等会写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.jupiter</groupId>
                    <artifactId>junit-jupiter-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

添加配置

在resources目录下创建应用的配置文件application.yml,我们这里使用8081,8080端口留给RESTful web服务,添加如下配置内容:

# 用来修改web服务的端口
server:
  port: 8081

编写代码

自定义RestTemplate

@Bean
public RestTemplate customRestTemplate(){
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(3000);
        httpRequestFactory.setConnectTimeout(3000);
        httpRequestFactory.setReadTimeout(3000);
 
        return new RestTemplate(httpRequestFactory);
}

定义统一响应VO R

@Data
public class R<T> implements Serializable {
    private static final String DEFAULT_SUCCESS_MSG = "请求成功";
    private static final int DEFAULT_SUCCESS_CODE = 0;
    public static final int SUCCESS = DEFAULT_SUCCESS_CODE;
    private Integer code;
    private String msg;
    private T data;
    public static<T> R ok(T data){
        R jsonResult = new R();
        jsonResult.setCode(DEFAULT_SUCCESS_CODE);
        jsonResult.setMsg(DEFAULT_SUCCESS_MSG);
        jsonResult.setData(data);
        return jsonResult;
    }
    public static<T> R err(int code, String msg , T data){
        R jsonResult = new R();
        jsonResult.setCode(code);
        jsonResult.setMsg(msg);
        jsonResult.setData(data);
        return jsonResult;
    }
    public static<T> R err(int code, String msg){
        R jsonResult = new R();
        jsonResult.setCode(code);
        jsonResult.setMsg(msg);
        return jsonResult;
    }
}

定义User请求VO

@Data
public class UserReqVO implements Serializable {

    private String username;
    private String password;

}

定义User响应VO

@Data
public class UserRespVO implements Serializable {

    private Integer id;
    private String username;
    private Date createTime;
}

编写UserClient使用restTemplate访问接口

@Component
@Slf4j
public class UserClient {

    @Resource
    RestTemplate restTemplate;

    public R<UserRespVO> getForObject(Integer id){
        Map<String, Object> uriVariables = new HashMap<>(1);
        uriVariables.put("id", id);
        R r = restTemplate.getForObject("http://localhost:8080/v1/user/{id}", R.class, uriVariables);
        return r;
    }

    public R<UserRespVO> getForEntity(Integer id){
        Map<String, Object> uriVariables = new HashMap<>(1);
        uriVariables.put("id", id);
        ResponseEntity<R> r = restTemplate.getForEntity("http://localhost:8080/v1/user/{id}", R.class,uriVariables);
        log.info(r.getHeaders().toString());
        return r.getBody();
    }

    public R<Boolean>  postForObject(UserReqVO userReqVO){
        R r = restTemplate.postForObject("http://localhost:8080/v1/user", userReqVO, R.class);
        return r;
    }

    public R<Boolean> postForEntity(UserReqVO userReqVO){
        ResponseEntity<R> r = restTemplate.postForEntity("http://localhost:8080/v1/user", userReqVO, R.class);
        log.info(r.getHeaders().toString());
        return r.getBody();
    }

    /**
     *  exchange 是一个通用且统一的方法,它既能发送 GET 和 POST 请求,也能用于发送其他各种类型的请求。
     * @return
     */
    public R<UserRespVO> exchange(Integer id){
        Map<String, Object> uriVariables = new HashMap<>(1);
        uriVariables.put("id", id);
        ResponseEntity<R> r = restTemplate.exchange("http://localhost:8080/v1/user/{id}", HttpMethod.GET, null, R.class, uriVariables);
        log.info(r.getHeaders().toString());
        return r.getBody();
    }

    public R<Boolean> put(Integer id, UserReqVO userReqVO){
        restTemplate.put("http://localhost:8080/v1/user/{id}", userReqVO, id);
        return R.ok(true);
    }

    public R<Boolean> delete(Integer id){
        restTemplate.delete("http://localhost:8080/v1/user/{id}", id);
        return R.ok(true);
    }
}
  • getForObject() 发送一个HTTP GET请求,返回的请求体将映射为业务对象

  • getForEntity() 发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的业务对象,在这个对象中还包含了 HTTP 消息头等信息,而且getForObject方法返回的只是业务对象

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

  • postForEntity() POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得 到的,和getForEntity类似,ResponseEntity对象中还包含了HTTP消息头等信息。

  • put() PUT 资源到特定的URL

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

  • exchange() 在URL上执行特定的HTTP方法,是一个通用且统一的方法,它既能发送 GET 和 POST 请求,也能用于发送其他各种类型的请求。返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的,同时包含了HTTP消息头等信息。

单元测试

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class UserClientTest {

    @Resource
    UserClient userClient;

    @Test
    public void getForObject() {

        R r = userClient.getForObject(9991);
        log.info("result : {}", r);
    }
    @Test
    public void getForEntity() {
         R r = userClient.getForEntity(9991);
         log.info("result : {}", r);
    }
    @Test
    public void postForObject() {
        UserReqVO userReqVO = new UserReqVO();
        userReqVO.setUsername("张三");
        userReqVO.setPassword("123456");
        R r = userClient.postForObject(userReqVO);
        log.info("result : {}", r);
    }
    @Test
    public void postForEntity() {
        UserReqVO userReqVO = new UserReqVO();
        userReqVO.setUsername("张三");
        userReqVO.setPassword("123456");
        R r = userClient.postForEntity(userReqVO);
        log.info("result : {}", r);
    }
    @Test
    public void exchange() {
        R r = userClient.exchange(9991);
        log.info("result : {}", r);
    }
    @Test
    public void put() {
        UserReqVO userReqVO = new UserReqVO();
        userReqVO.setUsername("张三");
        userReqVO.setPassword("123456");
        R r = userClient.put(1,userReqVO);
        log.info("result : {}", r);
    }
    @Test
    public void delete() {
        R r = userClient.delete(1);
        log.info("result : {}",r);
    }
}

小结

我们在Spring Boot构建RESTful风格Web服务的基础,通过引入RestTemplate模板实现了对远程服务接口的访问,RestTemplate 为开发人员提供了一大批有用的工具方法来实现 HTTP 请求的发送以及响应的获取。同时,该模板类还开发了一些定制化的入口供开发人员嵌入,用来实现对 HTTP 请求过程进行精细化管理的处理逻辑。和 JdbcTemplate 一样,RestTemplate 在设计和实现上也是一款非常有效的工具类。希望这个简单的入门对您有帮忙~

最后说一句

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下,您的支持是我坚持写作最大的动力,多谢支持。

此外,关注公众号:黑色的灯塔,专注Java后端技术分享,涵盖Spring,Spring Boot,SpringCloud,Docker,Kubernetes中间件等技术。