这节的要点:
就是弄两个项目 , 从 端口9090 这个项目,通过 webClient, 去访问 端口8080 的项目,并获取8080项目的数据。
★ RESTful客户端的两种方式
- 应用基于传统的Spring MVC框架,此时考虑使用RestTemplate来整合第三方RESTful服务。RestTemplate就属于传统Spring Web的API。- 应用基于传统的Web Flux框架,此时考虑使用WebClient来整合第三方RESTful服务。WebClient本身就是属于WebFlux API
★ 使用WebClient调用(整合)第三方RESTful服务
如果应用本身使用的WebFlux这种反应式API,使用WebClient来整合第三饭RESTful服务会更好一些。与RestTemplate的区别在于:
它采用的函数式的编程方式,且它返回的数据都是Flux或Mono——它是面向消息发布来编程
Flux(要返回多条数据用这个 Flux 返回类型)
Mono(只返回一条数据用这个 Mono 返回类型)同样使用的反应式、非阻塞的API。使用:
(1)通过预配置的WebClient.Builder对象创建WebClient。不要自己去new一个WebClient(2)调用WebClient对象的如下方法来指定发送请求: delete()|get()|head() |method(HttpMethod method) |patch()|post() |put()
调用如下方法来设置请求头和请求体。
uri() | header() | accept() | body()
调用如下两个方法获取响应:
exchange()| retrieve()
★ WebClient的底层配置
WebClient底层需要依赖自动配置的ClientHttpConnector(HTTP连接器)▲ Spring Boot会根据类加载路径里的类库自动检测使用哪个ClientHttpConnector来驱动WebClient,Spring Boot内置支持Netty的ReactorClientHttpConnector和JettyClientHttpConnector两个实现类。▲ Spring Boot默认会选择ReactorClientHttpConnector作为实现类(它底层依赖于Reactor Netty),Reactor Netty可以同时提供服务器和客户端的实现;- 只要你添加WebFlux的依赖库(spring-boot-starter-webflux),Netty既能提供服务器端的支持,也能提供WebClient所需要的ClientHttpConnector。一句话,你只需要添加spring-boot-starter-webflux,剩下的一切都搞定。- 如果要选择Jetty作为WebFlux应用的服务器(它只能提供服务器端的支持),如果需要WebClient的客户端支持,那就还需要添加Jetty Reactive HTTPClient的客户端JAR包。
★ 对客户端和服务器端同时配置:
两步:(1)在Spring容器中配置自定义的ReactorResourceFactory(对于Reactor Netty)或JettyResourceFactory(对Jetty生效)。(2)Spring Boot会自动加载、并应用它们对Reactor Netty或Jetty的资源配置进行重写,这样可同时作用于服务器端和客户端。
★ 替换ClientHttpConnector【一般很少这么干,因为这样相当于完全放弃了Spring Boot的自动配置】
只要在Spring容器中配置自己的ClientHttpConnector,Spring Boot就不会再帮我们自动配置ClientHttpConnector。这样就使用了自定义的ClientHttpConnector代替了自动配置的ClientHttpConnector。
★ 定制WebClient(做法完全类似于前面定制RestTemplate)
定制WebClient提供了两种方式:
- 局部式:在调用WebClient.Builder的build()方法构建WebCilent之前,先调用WebClient.Builder的方法对其定制,通过这种方式设置的WebClient.Builder仅对它构建的WebClient起作用。- 全局式:使用WebClientCustomizer进行定制,所有实现WebClientCustomizer接口的Bean会被自动应用到自动配置的WebClient.Builder中,这种定制方式对整个应用范围的WebClient都起作用。—— 此处的定制方式与定制RestTemplate几乎是相同的。
代码演示
RESTful_XML 8080 项目代表 restful 服务的 服务端,生成json响应的,
MyWebClient9090 项目代表 restful 服务的 客户端,发起请求的
这个 RESTful_XML 就是第三方RESTful 服务,MyWebClient 项目通过 WebClient 来整合它
其他代码可以在这篇获取,都是一样的
其他代码是基于这篇—SpringBoot 使用RestTemplate 整合第三方 RESTful 服务 – 延伸的
需求:两个项目 , 从 9090 这个项目,通过 WebClient 去访问 8080 的项目,并获取数据。
WebClient 和 RestTemplate 的区别
WebClient 属于 WebFlux 的 API , 因此需要导入 WebFlux 的依赖库
先导入依赖:
区别:
WebClient 和 RestTemplate 的依赖注入的区别
WebClient 和 RestTemplate 的查看所有图书区别
根据id查看图书
根据id删除图书
webClient可以把被删除的对象返回回来
查看测试结果
根据id修改图书数据
测试结果
完整代码
其他代码可以在这篇获取,都是一样的
其他代码是基于这篇—SpringBoot 使用RestTemplate 整合第三方 RESTful 服务 – 延伸的
pom.xml
ClientController
package cn.ljh.app.controller;import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.util.Map;@RestController
@RequestMapping("/mybooks")
public class ClientController
{private final WebClient webClient;public ClientController(WebClient.Builder builder){/** 此处的 WebClient.Builder 是来自于Spring 容器的注入,* 因此它所构建的 webClient 已经接收了spring 容器的默认设置* 如果直接创建 WebClient , 那就相当于完全没有利用Spring容器的依赖注入,* 因此完全不能接受spring容器的默认配置,这样后面所介绍的配置 webClient 完全不可能实现配置了*/this.webClient = builder//此处本身就是对 webClient 的定制.baseUrl("http://192.168.43.189:8080/") //webClient 指定基路径//此处还可以对 webClient 进行更多的定制//.............build();}//查看所有图书@GetMapping("/viewBooks")public Flux<Map> viewBooks(){Flux<Map> mapFlux = webClient.get().uri("/books/viewBooks") //访问路径.accept(MediaType.APPLICATION_JSON) //访问该方法,希望接收响应类型.retrieve() //获取响应数据//将响应数据转换成 Flux(响应集合数据用Flux) 或这 Mono(单个响应数据用 Mono).bodyToFlux(Map.class);return mapFlux;}//根据id查看图书@GetMapping("/{id}")public Mono<Map> getBookById(@PathVariable Integer id){Mono<Map> mapMono = webClient.get().uri("/books/"+id ) //由于地址是静态的,所以可以把id拼接上去.accept(MediaType.APPLICATION_JSON).retrieve()//获取响应,这里的响应不是真正的数据//将响应数据转换成 Flux(响应集合数据用Flux) 或这 Mono(单个响应数据用 Mono).bodyToMono(Map.class); //获取的属于是消息发布者,或者说是一个消息通道return mapMono;}//根据id删除图书@DeleteMapping("/{id}")public Mono<Map> deleteBookById(@PathVariable Integer id){//webClient可以把被删除的对象返回回来Mono<Map> mapMono = webClient.delete().uri("/books/" + id).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(Map.class);return mapMono;}//根据id修改图书@PutMapping("/{id}")public Mono<Map> updateById(@PathVariable Integer id,@RequestBody Map requestData){Mono<Map> mapMono = webClient.put().uri("/books/" + id).accept(MediaType.APPLICATION_JSON)//参数1:看源码,需要是消息发布者,,因为请求参数只有一个数据,不是集合,所以可以把请求参数包装成Mono,安全一些//参数2:指定参数数据的类型.body(Mono.justOrEmpty(requestData), Map.class)//.header() //如果有需要,可以这样指定请求头.retrieve() //获取响应数据.bodyToMono(Map.class);return mapMono;}}
pom.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>2.4.5</version></parent><groupId>cn.ljh</groupId><artifactId>MyWebClient</artifactId><version>1.0.0</version><name>MyWebClient</name><properties><java.version>11</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- <dependency>--><!-- <groupId>org.springframework.boot</groupId>--><!-- <artifactId>spring-boot-starter-web</artifactId>--><!-- </dependency>--><!-- WebClient 属于 WebFlux 的 API , 因此需要导入 WebFlux 的依赖库 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>