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 {@Testvoid 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);}
}