# Spring Boot `RestTemplate`

> 原文： [http://zetcode.com/springboot/resttemplate/](http://zetcode.com/springboot/resttemplate/)

Spring Boot `RestTemplate`教程展示了如何在 Spring 应用中使用`RestTemplate`创建同步 HTTP 请求。

Spring 是流行的 Java 应用框架，而 Spring Boot 是 Spring 的演进，可以帮助轻松地创建独立的，生产级的基于 Spring 的应用。

## `RestTemplate`

`RestTemplate`是执行 HTTP 请求的同步客户端。 它在基础 HTTP 客户端库（例如 JDK `HttpURLConnection`，Apache HttpComponents 等）上使用简单的模板方法 API。

从 Spring 5.0 开始，可以使用新客户端`WebClient`创建同步和异步请求。 在将来的版本中，将不推荐使用`RestTemplate`，而推荐使用`WebClient`。

## Spring Boot `RestTemplate` 示例

在以下应用中，我们创建一个自定义测试服务器，该服务器生成 JSON 数据，并使用`RestTemplate`生成 HTTP 请求并使用返回的 JSON 数据。

## 创建 JSON 服务器

为此，我们使用 Node 创建一个 JSON 测试服务器。

```java
$ node --version
v11.2.0

```

我们显示 Node 的版本。

```java
$ npm init    
$ npm i -g json-server
$ npm i faker fs

```

我们初始化 Node 项目并安装`json-server`，`faker`和`fs`模块。 `json-server`用于创建测试 JSON 服务器，`faker`用于生成测试数据，`fs`用于 JavaScript 中的文件系统。

`generate_fake_users.js`

```java
const faker = require('faker')
const fs = require('fs')

function generateUsers() {

    let users = []

    for (let id=1; id <= 100; id++) {

        let firstName = faker.name.firstName()
        let lastName = faker.name.lastName()
        let email = faker.internet.email()

        users.push({
            "id": id,
            "first_name": firstName,
            "last_name": lastName,
            "email": email
        })
    }

    return { "users": users }
}

let dataObj = generateUsers();

fs.writeFileSync('data.json', JSON.stringify(dataObj, null, '\t'));

```

使用仿造者，我们可以生成具有 ID，名字，姓氏和电子邮件属性的一百个用户。 数据被写入`data.json`文件。 该文件由`json-server`使用。

```java
$ node generate_fake_users.js

```

我们产生了一百个假用户。

```java
$ json-server --watch data.json

\{^_^}/ hi!

Loading data.json
Done

Resources
http://localhost:3000/users

Home
http://localhost:3000

```

我们开始`json-server`。 现在，我们可以向`http://localhost:3000/users`资源创建一个请求，以使用 JSON 获得一百个用户。

## Spring Boot 应用

我们创建一个 Spring Boot 应用。 我们需要以下 Maven 依赖项和插件：`spring-boot-starter`，`spring-web`，`jackson-databind`，`spring-boot-starter-test`和`spring-boot-maven-plugin`。

`application.properties`

```java
spring.main.banner-mode=off
logging.level.root=INFO
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n

myrest.url=http://localhost:3000/users

```

`application.properties`是 Spring Boot 中的主要配置文件。 我们关闭 Spring 横幅，将日志记录级别设置为 info，并设置控制台日志记录模式。 我们还设置了一个指向用户资源的 URL 属性。 稍后将使用`@Value`检索该属性。

`User.java`

```java
package com.zetcode.bean;

import com.fasterxml.jackson.annotation.JsonProperty;

public class User {

    private int id;
    private String firstName;
    private String lastName;
    private String email;

    public int getId() {

        return id;
    }

    public void setId(int id) {

        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    @JsonProperty("first_name")
    public void setFirstName(String firstName) {

        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @JsonProperty("last_name")
    public void setLastName(String lastName) {

        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {

        this.email = email;
    }

    @Override
    public String toString() {

        final var sb = new StringBuilder("User{");
        sb.append("id=").append(id);
        sb.append(", firstName='").append(firstName).append('\'');
        sb.append(", lastName='").append(lastName).append('\'');
        sb.append(", email='").append(email).append('\'');
        sb.append('}');

        return sb.toString();
    }
}        

```

`User` bean 映射到 JSON 用户对象。 Spring 使用 Jackson 库将 JSON 数据绑定到 Java 类。 由于 JSON 属性与 Java 属性不匹配，因此我们使用`@JsonProperty`来解决此问题。

`AppConfig.java`

```java
package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {

        var factory = new SimpleClientHttpRequestFactory();

        factory.setConnectTimeout(3000);
        factory.setReadTimeout(3000);

        return new RestTemplate(factory);
    }
}

```

我们创建一个配置 bean。 设置`RestTemplate`。 `SimpleClientHttpRequestFactory`用于设置连接和读取超时。

`AppConfig.java`

```java
package com.zetcode.config;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {

        return builder
                .setConnectTimeout(Duration.ofMillis(3000))
                .setReadTimeout(Duration.ofMillis(3000))
                .build();
    }
}

```

或者，我们可以使用`RestTemplateBuilder`来完成这项工作。

`MyRestService.java`

```java
package com.zetcode.service;

import com.zetcode.bean.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class MyRestService {

    @Autowired
    private RestTemplate myRestTemplate;

    @Value("${myrest.url}")
    private String restUrl;

    public User[] getUsers() {

        var users = myRestTemplate.getForObject(restUrl, User[].class);

        return users;
    }
}       

```

`MyRestService`是生成 HTTP 请求的服务类。 它从 JSON 测试服务器获取所有用户。

```java
@Autowired
private RestTemplate myRestTemplate;

```

我们注入了`RestTemplate` bean。

```java
@Value("${myrest.url}")
private String restUrl;

```

从配置中，我们使用`@Value`注解获取 URL。

```java
var users = myRestTemplate.getForObject(restUrl, User[].class);

```

我们使用`getForObject()`方法生成请求。 由于我们期望对象数组，因此我们使用`User[].class`语法。

`MyRunner.java`

```java
package com.zetcode;

import com.zetcode.service.MyRestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);

    @Autowired
    private MyRestService myRestService;

    @Override
    public void run(String... args) throws Exception {

        var users = myRestService.getUsers();

        Arrays.stream(users).limit(10).forEach(todo -> logger.info("{}", todo));
    }
}

```

`MyRunner`使用`MyRestService`获取用户。 我们向控制台显示前十个用户。

`Application.java`

```java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);
    }
}

```

`Application`是设置 Spring Boot 应用的入口。

`ApplicationTests.java`

```java
package com.zetcode;

import com.zetcode.config.AppConfig;
import com.zetcode.service.MyRestService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@RestClientTest(value={MyRestService.class, AppConfig.class})
public class ApplicationTests {

    @Autowired
    private MyRestService service;

    @Test
    public void usersNotEmpty() throws Exception {

        var users = this.service.getUsers();
        assertThat(users).isNotEmpty();
    }

    @Test
    public void hasSizeOneHundred() throws Exception {

        var users = this.service.getUsers();
        assertThat(users).hasSize(100);

        System.out.println(users);
    }
}

```

我们测试`getUsers()`服务方法。 我们测试 JSON 数据不为空，并且包含一百个元素。

```java
@RestClientTest(value={MyRestService.class, AppConfig.class})

```

`@RestClientTest`注解用于测试 Spring rest 客户端。 它禁用完全自动配置，并且仅应用与其余客户端测试相关的配置。

```java
$ mvn -q spring-boot:run
...
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=1, firstName='Ofelia', lastName='Hintz', email='Gustave.Von43@yahoo.com'}
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=2, firstName='Brian', lastName='Marvin', email='Marina.Shields@hotmail.com'}
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=3, firstName='Adah', lastName='Marquardt', email='Osbaldo_Halvorson55@hotmail.com'}
27-11-2018 15:33:55 [main] INFO  com.zetcode.MyRunner.lambda$run$0 - User{id=4, firstName='Jaycee', lastName='Kulas', email='Claud85@gmail.com'}
...

```

我们运行该应用。

在本教程中，我们展示了如何在 Spring 应用中使用`RestTemplate`创建同步请求。 REST 数据来自 Node 创建的测试 JSON 服务器。 您可能也对相关教程感兴趣： [Spring Boot `@RestController`教程](/springboot/restcontroller/)， [Spring Boot H2 REST 教程](/articles/springbootresth2/)， [Spring Boot RESTFul 应用](/articles/springbootrestsimple/)， [Spring Boot REST Data JPA 教程](/articles/springbootrestdatajpa/)和 [Java 教程](/lang/java/)。