SpringBoot是一个基于Spring的快速开发框架,它可以帮助我们快速构建、部署和运行Java应用程序。HTTP接口是Web应用程序与外部系统进行通信的一种方式,通过HTTP协议,我们可以实现客户端与服务器之间的数据交互。
SpringBoot 整合提供了很多方式进行远程调用
- 轻量级客户端方式
RestTemplate
: 普通开发WebClient
: 响应式编程开发Http Interface
: 声明式编程
在 Spring WebFlux 中,Mono 和 Flux 都是响应式编程的工具,用于处理异步数据流。
Mono
: 是一个单例的、不可变的、最终的、完成的、包含单个元素的数据流,它只能发出一个元素。
Flux
: 是一个可变的、无限的、最终的、未完成的数据流,它可以发出任意数量的元素。
声明式客户端
声明式 http 客户端主旨是使得编写 java http 客户端更容易。为了贯彻这个理念,采用了通过处理注解来自动生成请求的方式(官方称呼为声明式、模板化)。通过声明式 http 客户端实现我们就可以在 java 中像调用一个本地方法一样完成一次 http 请求,大大减少了编码成本,同时提高了代码可读性。
测试环境
SpringBoot3.0.6,JDK17
1. WebClient
WebClient 是Spring WebFlux 模块提供的一个非阻塞的基于响应式编程的进行 Http 请求的客户端工具。完全非阻塞,支持流式处理。
1.1 创建与配置
发请求:
- 请求方式: GET\POST\DELETE…
- 请求路径: /…
- 请求参数:aa=bb&cc=dd&xxx
- 请求头: aa=bb,cc=ddd
- 请求体:
创建WebClient
: WebClient.create()
WebClient.create(String baseUrl)
使用WebClient.builder()
配置更多参数:uriBuilderFactory
: 自定义UriBuilderFactory
,定义 baseurl.defaultUriVariables
: 默认 uri 变量.defaultHeader
: 每个请求默认头.defaultCookie
: 每个请求默认 cookie.defaultRequest
: Consumer 自定义每个请求.filter
: 过滤 client 发送的每个请求exchangeStrategies
: HTTP 消息 reader/writer 自定义.clientConnector
: HTTP client 库设置.
pom依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
WebClient webClient = WebClient.create("https://api.qqsuu.cn");
1.2 获取响应
retrieve()
方法用来声明如何提取响应数据。比如
//获取响应完整信息 WebClient client = WebClient.create("https://example.org"); Mono<ResponseEntity<Person>> result = client.get() .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON) .retrieve() .toEntity(Person.class); //只获取body WebClient client = WebClient.create("https://example.org"); Mono<Person> result = client.get() .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(Person.class); //stream数据 Flux<Quote> result = client.get() .uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM) .retrieve() .bodyToFlux(Quote.class); //定义错误处理 Mono<Person> result = client.get() .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON) .retrieve() .onStatus(HttpStatus::is4xxClientError, response -> ...) .onStatus(HttpStatus::is5xxServerError, response -> ...) .bodyToMono(Person.class);
1.3 定义请求体
//1、响应式-单个数据 Mono<Person> personMono = ... ; Mono<Void> result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .body(personMono, Person.class) .retrieve() .bodyToMono(Void.class); //2、响应式-多个数据 Flux<Person> personFlux = ... ; Mono<Void> result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_STREAM_JSON) .body(personFlux, Person.class) .retrieve() .bodyToMono(Void.class); //3、普通对象 Person person = ... ; Mono<Void> result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .bodyValue(person) .retrieve() .bodyToMono(Void.class);
2. HTTP Interface
从 Spring 6 和 Spring Boot 3 开始,Spring 框架支持将远程 HTTP 服务代理成带有特定注解的 Java http interface。类似的库,如 OpenFeign 和 Retrofit 仍然可以使用,但 http interface 为 Spring 框架添加内置支持。
HTTP Interface可以将 HTTP 服务定义成一个包含特定注解标记的方法的 Java 接口,然后通过对接口方法的调用,完成 HTTP 请求。
2.1 定义接口
public interface BingService { @GetExchange(url = "/search") String search(@RequestParam("keyword") String keyword); }
2.2 创建代理&测试
@SpringBootTest class Boot05TaskApplicationTests { @Test void contextLoads() throws InterruptedException { //1、创建客户端 WebClient client = WebClient.builder() .baseUrl("https://cn.bing.com") .codecs(clientCodecConfigurer -> { clientCodecConfigurer .defaultCodecs() .maxInMemorySize(256*1024*1024); //响应数据量太大有可能会超出BufferSize,所以这里设置的大一点 }) .build(); //2、创建工厂 HttpServiceProxyFactory factory = HttpServiceProxyFactory .builder(WebClientAdapter.forClient(client)).build(); //3、获取代理对象 BingService bingService = factory.createClient(BingService.class); //4、测试调用 Mono<String> search = bingService.search("chatgpt是什么"); System.out.println("=========="); //return search; search.subscribe(str -> System.out.println(str)); Thread.sleep(100000); } }