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 测试服务器。
$ node --version
v11.2.0
我们显示 Node 的版本。
$ npm init
$ npm i -g json-server
$ npm i faker fs
我们初始化 Node projet 并安装json-server
,faker
和fs
模块。 json-server
用于创建测试 JSON 服务器,faker
用于生成测试数据,fs
用于 JavaScript 中的文件系统。
generate_fake_users.js
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 使用。
$ node generate_fake_users.js
我们产生了一百个假用户。
$ 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
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
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
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
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
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 测试服务器获取所有用户。
@Autowired
private RestTemplate myRestTemplate;
我们注入了RestTemplate
bean。
@Value("${myrest.url}")
private String restUrl;
从配置中,我们使用@Value
注解获取 URL。
var users = myRestTemplate.getForObject(restUrl, User[].class);
我们使用getForObject()
方法生成请求。 由于我们期望对象数组,因此我们使用User[].class
语法。
MyRunner.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
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
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 数据不为空,并且包含一百个元素。
@RestClientTest(value={MyRestService.class, AppConfig.class})
@RestClientTest
注解用于测试 Spring rest 客户端。 它禁用完全自动配置,并且仅应用与其余客户端测试相关的配置。
$ 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 服务器。