spring boot 外部 API 调用 ----22

📅 2026/8/1 3:09:10 👁️ 阅读次数 📝 编程学习
spring boot 外部 API 调用 ----22

 

 

覆盖 Spring Boot 3 官方推荐的两种调用方式:RestClient(命令式灵活调用) + HTTP Service Client(声明式接口调用)。基于公开测试接口 JSONPlaceholder 演示,无需额外搭建服务,复制即可运行,严格遵循生产级最佳实践。

一、项目结构

plaintext
 
 
com.example.apicall
├── ApiCallApplication.java        # 启动类
├── entity
│   └── Post.java                  # 通用响应实体
├── config
│   └── ApiClientConfig.java       # 客户端统一配置
├── client
│   └── JsonPlaceholderApi.java    # 声明式HTTP接口
└── service├── RestClientDemoService.java # RestClient用法演示└── HttpServiceDemoService.java# 声明式调用演示
└── controller└── ApiTestController.java     # 测试接口

 

 

二、pom.xml 核心依赖

Spring Boot 3.x 内置 RestClientHTTP Service,只需 Web 基础依赖即可,无需额外第三方包。
xml
 
 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0</version></parent><groupId>com.example</groupId><artifactId>rest-api-call-demo</artifactId><version>1.0.0</version><properties><java.version>17</java.version></properties><dependencies><!-- Web 基础:内置 RestClient + HTTP Service 能力 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Lombok 简化代码 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies>
</project>

 

 

三、通用响应实体

模拟外部接口返回的帖子数据,对接公开测试接口 jsonplaceholder.typicode.com
java
 
运行
 
 
package com.example.apicall.entity;import lombok.Data;@Data
public class Post {private Integer id;private Integer userId;private String title;private String body;
}

 


四、第一部分:RestClient 灵活调用(对应 227、228 集)

Spring 6 推出的现代 HTTP 客户端,替代旧版 RestTemplate,流式 API 更简洁,支持同步调用。

1. 配置类(生产级最佳实践)

统一配置 baseUrl、超时、默认请求头,注册为 Spring Bean,避免每次调用重复创建。
java
 
运行
 
 
package com.example.apicall.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestClient;@Configuration
public class ApiClientConfig {/*** RestClient 客户端 Bean* 对应227集:现代REST调用方式* 最佳实践:预配置baseUrl、超时时间、默认头,复用实例*/@Beanpublic RestClient jsonPlaceholderRestClient() {// 配置超时:连接3秒,读取5秒,防止外部接口卡住SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();factory.setConnectTimeout(3000);factory.setReadTimeout(5000);return RestClient.builder().baseUrl("https://jsonplaceholder.typicode.com").defaultHeader("Content-Type", "application/json").requestFactory(factory).build();}
}

 

2. 业务服务类(基础 + 高级用法)

java
 
运行
 
 
package com.example.apicall.service;import com.example.apicall.entity.Post;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;import java.util.List;@Service
@RequiredArgsConstructor
public class RestClientDemoService {private final RestClient jsonPlaceholderRestClient;/*** 1. 基础GET:根据ID查询单条数据* 对应227集:简单GET调用*/public Post getPostById(Integer id) {return jsonPlaceholderRestClient.get().uri("/posts/{id}", id)    // 路径参数占位符.retrieve()                 // 发起请求并解析响应.body(Post.class);          // 响应体自动转成Java对象
    }/*** 2. 基础GET:查询列表*/public List<Post> getAllPosts() {return jsonPlaceholderRestClient.get().uri("/posts").retrieve().body(List.class);}/*** 3. POST请求:提交数据* 对应228集:超出简单GET的高级用法*/public Post createPost(Post post) {return jsonPlaceholderRestClient.post().uri("/posts").body(post)                 // 请求体
                .retrieve().body(Post.class);}/*** 4. 高级:自定义异常处理 + 获取响应状态* 对应228集:错误处理、状态码判断*/public Post getPostWithErrorHandle(Integer id) {return jsonPlaceholderRestClient.get().uri("/posts/{id}", id).retrieve()// 4xx/5xx 状态码自定义处理.onStatus(status -> status.is4xxClientError(), (req, resp) -> {throw new RuntimeException("客户端错误,状态码:" + resp.getStatusCode());}).onStatus(status -> status.is5xxServerError(), (req, resp) -> {throw new RuntimeException("外部服务异常");}).body(Post.class);}
}

 

 

五、第二部分:HTTP Service Client 声明式调用(对应 229~231 集)

类似 OpenFeign 的声明式写法,只需要定义接口,Spring 自动生成实现,代码更简洁,维护性更强,是固定接口调用的首选方案。

1. 声明式接口定义

java
 
运行
 
 
package com.example.apicall.client;import com.example.apicall.entity.Post;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.PostExchange;
import org.springframework.web.service.annotation.HttpExchange;import java.util.List;/*** 声明式HTTP接口* 对应229集:声明式REST调用* 只写接口和注解,Spring自动生成实现类*/
@HttpExchange("/posts")
public interface JsonPlaceholderApi {// 查询单条@GetExchange("/{id}")Post getPostById(Integer id);// 查询列表
    @GetExchangeList<Post> listPosts();// 新建
    @PostExchangePost createPost(Post post);
}

 

2. 注册为 Spring Bean(配置类补充)

ApiClientConfig.java 中追加 Bean 定义,通过代理工厂创建接口实现。
java
 
运行
 
 
/*** HTTP Service 声明式客户端 Bean* 对应230集:消费REST API* 对应231集:按服务分组管理,不同服务对应不同接口Bean*/
@Bean
public JsonPlaceholderApi jsonPlaceholderApi(RestClient.Builder builder) {// 复用RestClient的配置能力作为底层客户端RestClient restClient = builder.baseUrl("https://jsonplaceholder.typicode.com").defaultHeader("Content-Type", "application/json").build();// 创建代理工厂,生成接口实现return HttpServiceProxyFactory.builderFor(RestClientAdapter.create(restClient)).build().createClient(JsonPlaceholderApi.class);
}

 

3. 使用示例

java
 
运行
 
 
package com.example.apicall.service;import com.example.apicall.client.JsonPlaceholderApi;
import com.example.apicall.entity.Post;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;import java.util.List;@Service
@RequiredArgsConstructor
public class HttpServiceDemoService {// 直接注入声明式接口,和调用本地方法一样private final JsonPlaceholderApi jsonPlaceholderApi;public Post getPost(Integer id) {return jsonPlaceholderApi.getPostById(id);}public List<Post> listPosts() {return jsonPlaceholderApi.listPosts();}public Post addPost(Post post) {return jsonPlaceholderApi.createPost(post);}
}

 

 
💡 分组说明(对应 231 集):如果有多个外部服务,就定义多个接口 + 多个 Bean,每个对应不同的 baseUrl,按服务分组管理,结构清晰互不干扰。

六、测试接口 Controller

java
 
运行
 package com.example.apicall.controller;import com.example.apicall.entity.Post;
import com.example.apicall.service.HttpServiceDemoService;
import com.example.apicall.service.RestClientDemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/api/test")
@RequiredArgsConstructor
public class ApiTestController {private final RestClientDemoService restClientDemoService;private final HttpServiceDemoService httpServiceDemoService;// ===== RestClient 测试 =====@GetMapping("/rest/post/{id}")public Post restGetPost(@PathVariable Integer id) {return restClientDemoService.getPostById(id);}@PostMapping("/rest/post")public Post restCreatePost(@RequestBody Post post) {return restClientDemoService.createPost(post);}// ===== HTTP Service 测试 =====@GetMapping("/http/post/{id}")public Post httpGetPost(@PathVariable Integer id) {return httpServiceDemoService.getPost(id);}@GetMapping("/http/posts")public List<Post> httpListPosts() {return httpServiceDemoService.listPosts();}
}

 


七、启动类

java
 
运行
 
 
package com.example.apicall;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ApiCallApplication {public static void main(String[] args) {SpringApplication.run(ApiCallApplication.class, args);}
}

 

 

八、课程对应表

表格
 
集数核心内容对应代码
226 REST API 消费者概念 前置说明 + 整体设计
227 RestClient 现代 REST 调用方式 RestClient 配置 + 基础 GET 方法
228 RestClient 高级用法(POST、错误处理) createPost、异常状态码处理
229 HTTP Service Client 声明式调用介绍 JsonPlaceholderApi 接口定义
230 用 HTTP Service 消费 REST 接口 接口代理 Bean + 服务层调用
231 HTTP Service 分组管理 按服务拆分接口 + 独立 Bean 的设计

九、最佳实践总结

  1. 选型原则
    • 固定接口、标准化调用 → 优先用 HTTP Service,代码最少、维护性最强
    • 动态 URL、复杂请求、需要精细控制 → 用 RestClient
    • 旧项目兼容可保留 RestTemplate,新项目直接上 RestClient
  2. 配置规范
    • 统一抽取 baseUrl、超时、公共头到配置类,不要硬编码在业务代码里
    • 必须设置连接超时和读取超时,防止外部接口故障拖垮自身服务
    • 不同外部服务分组配置,各自独立 Bean,避免混淆
  3. 异常与容错
    • 对 4xx、5xx 状态码做分类处理,不要全吞异常
    • 生产环境建议配合重试、熔断组件(如 Resilience4j)
    • 外部调用必须打日志,记录入参、出参、耗时,方便排查问题