ZetCode

Spring Boot RestTemplate

最后修改于 2023 年 7 月 28 日

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

Spring 是一个流行的 Java 应用程序框架,而 Spring Boot 是 Spring 的一个演进,它有助于轻松创建独立的、生产级的基于 Spring 的应用程序。

RestTemplate

RestTemplate是一个用于执行HTTP请求的同步客户端。它使用一个简单的模板方法API,基于底层的HTTP客户端库,如JDK HttpURLConnection、Apache HttpComponents等。

自Spring 5.0起,一个新的客户端WebClient可用,可用于创建同步和异步请求。在未来的版本中,RestTemplate将被弃用,转而使用WebClient

Spring Boot RestTemplate示例

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

创建JSON服务器

我们使用Node来创建用于我们目的的JSON测试服务器。

$ node --version
v20.4.0

我们展示Node的版本。

$ npm init -y
$ npm i -g json-server
$ npm i @faker-js/faker fs

我们初始化一个Node项目并安装json-serverfakerfs模块。json-server用于创建测试JSON服务器,faker用于生成测试数据,而fs用于在JavaScript中处理文件系统。

generate_fake_users.js
import { faker } from '@faker-js/faker';
import { writeFileSync } from 'fs'

function generateUsers() {

    let users = []

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

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

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

    return { "users": users }
}

let dataObj = generateUsers();

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

使用faker,我们生成一百个用户,其中包含id、名字、姓氏和电子邮件属性。数据被写入data.json文件。该文件被json-server使用。

$ node generate_fake_users.js

我们生成一百个虚假用户。

$ json-server --watch data.json

\{^_^}/ hi!

Loading data.json
Done

Resources
https://:3000/users

Home
https://:3000

我们启动json-server。现在我们可以创建一个请求到https://:3000/users资源,以获取一百个JSON格式的用户。

Spring Boot应用程序

我们创建一个Spring Boot应用程序。我们需要以下Maven依赖项和插件:spring-boot-starterspring-webjackson-databindspring-boot-starter-testspring-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=https://:3000/users

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

com/zetcode/model/User.java
package com.zetcode.model;

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来修复此问题。

com/zetcode/config/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创建一个配置bean。它设置了RestTemplate。我们设置了连接和读取超时。

com/zetcode/service/MyRestService.java
package com.zetcode.service;

import com.zetcode.model.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 {

    private final RestTemplate myRestTemplate;

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

    @Autowired
    public MyRestService(RestTemplate myRestTemplate) {
        this.myRestTemplate = myRestTemplate;
    }

    public User[] getUsers() {

        return myRestTemplate.getForObject(restUrl, User[].class);
    }
}

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

@Autowired
public MyRestService(RestTemplate myRestTemplate) {
    this.myRestTemplate = myRestTemplate;
}

我们注入RestTemplate bean。

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

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

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

我们使用getForObject方法生成请求。由于我们期望一个对象数组,我们使用User[].class语法。

com/zetcode/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);

    private final MyRestService myRestService;

    @Autowired
    public MyRunner(MyRestService myRestService) {
        this.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获取用户。我们将前十个用户显示到控制台。

com/zetcode/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 应用程序的入口点。

com/zetcode/ApplicationTests.java
package com.zetcode;

import com.zetcode.config.AppConfig;
import com.zetcode.service.MyRestService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;

import java.util.Arrays;

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

@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(Arrays.toString(users));
    }
}

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

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

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

$ ./gradlew bootRun
...
... - User{id=1, firstName='Ofelia', lastName='Hintz', email='Gustave.Von43@yahoo.com'}
... - User{id=2, firstName='Brian', lastName='Marvin', email='Marina.Shields@hotmail.com'}
... - User{id=3, firstName='Adah', lastName='Marquardt', email='Osbaldo_Halvorson55@hotmail.com'}
... - User{id=4, firstName='Jaycee', lastName='Kulas', email='Claud85@gmail.com'}
...

我们运行应用程序。

在本文中,我们展示了如何使用RestTemplate在Spring应用程序中创建同步请求。REST数据来自Node创建的测试JSON服务器。

作者

我的名字是Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。自2007年以来,我一直在撰写编程文章。到目前为止,我撰写了1400多篇文章和8本电子书。我拥有超过十年的编程教学经验。

列出 所有 Spring Boot 教程