WebClient特性
什么是异步非阻塞
1.Maven依赖pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--WebClient-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</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>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.声明Todo数据类
@Data
public class Todo {
private Integer userId;
private Integer id;
private String title;
private Boolean completed;
}
3.声明服务接口
public interface TodoService {
// 一个方法就是一个远程服务(远程调用)
@GetExchange("/todos/{id}")
Todo getTodoById(@PathVariable("id") Integer id);
//增加资源
@PostExchange(value = "/todos/", accept = MediaType.APPLICATION_JSON_VALUE)
Todo createTodo(@RequestBody Todo newTodo);
//修改资源
@PutExchange("/todos/{id}")
ResponseEntity<Todo> modifyTodo(@PathVariable Integer id, @RequestBody Todo todo);
//删除资源
@DeleteExchange("/todos/{sid}")
void removeTodo(@PathVariable("sid") Integer id);
}
4.创建HTTP服务代理对象
//proxyBeanMethods = false:多实例对象,无论被取出多少此都是不同的bean实例,在该模式下SpringBoot每次启动会跳过检查容器中是否存在该组件
@Configuration(proxyBeanMethods = false)
public class HttpConfiguration {
//创建服务接口的代理对象,基于WebClient
@Bean
public TodoService requestService() {
WebClient webClient =
WebClient.builder().baseUrl("https://jsonplaceholder.typicode.com").build();
//创建代理工厂,设置超时时间
HttpServiceProxyFactory proxyFactory =
HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)).blockTimeout(Duration.ofSeconds(60)).build();
//创建某个接口的代理服务
return proxyFactory.createClient(TodoService.class);
}
}
5.单元测试
@SpringBootTest
class Springboot18HttpServiceApplicationTests {
//注入代理对象
@Resource
private TodoService todoService;
//测试访问todos/1
@Test
void testQuery() {
Todo todo = todoService.getTodoById(1);
System.out.println("todo = " + todo);
System.out.println(todo.getTitle());
}
//创建资源
@Test
void testCreateTodo() {
Todo todo = new Todo();
todo.setId(1222);
todo.setUserId(1223);
todo.setTitle("事项1");
todo.setCompleted(true);
Todo res = todoService.createTodo(todo);
System.out.println("res = " + res);
}
//修改资源
@Test
void testModify() {
Todo todo = new Todo();
todo.setId(1002);
todo.setUserId(5002);
todo.setTitle("事项2");
todo.setCompleted(true);
ResponseEntity<Todo> entity = todoService.modifyTodo(2, todo);
HttpHeaders headers = entity.getHeaders();
System.out.println("headers = " + headers);
Todo body = entity.getBody();
System.out.println("body = " + body);
HttpStatusCode statusCode = entity.getStatusCode();
System.out.println("statusCode = " + statusCode);
}
//删除资源
@Test
void testDelete() {
todoService.removeTodo(10);
}
}
@HttpExchange注解用于声明接口作为HTTP远程服务。在方法、类级别使用。通过注解属性以及方法的参数设置HTTP请求的细节。
快捷注解简化不同的请求方式:
作为HTTP服务接口中的方法允许使用的参数列表
1.创建Albums数据类
@Data
public class Albums {
private Integer id;
private Integer userId;
private String title;
}
2.创建AlbumsService接口
@HttpExchange(url = "https://jsonplaceholder.typicode.com/")
public interface AlbumsService {
//查询专辑
@HttpExchange(method = "GET",url = "/albums/{id}")
Albums getById(@PathVariable Integer id);
}
3.声明代理
@Bean
//创建代理
public AlbumsService albumsService() {
WebClient webClient = WebClient.create();
HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)).blockTimeout(Duration.ofSeconds(60)).build();
return proxyFactory.createClient(AlbumsService.class);
}
4.单元测试
@SpringBootTest
public class AlbumsServiceTest {
@Resource
private AlbumsService albumsService;
@Test
void testQuery() {
Albums albums = albumsService.getById(5);
System.out.println("albums = " + albums);
}
}
创建Albums的Java Record
public record AlbumsRecord(Integer id, Integer userId, String title) {
}
其余步骤一样
1.设置超时,异常处理
//定制HTTP服务
@Bean
public AlbumsService albumsService() {
//超时
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)//连接时间
.doOnConnected(conn -> {
conn.addHandlerLast(new ReadTimeoutHandler(10));//读超时
conn.addHandlerLast(new WriteTimeoutHandler(10));//写超时
});
//设置异常
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
//定制 4XX,5XX 的回调函数
.defaultStatusHandler(HttpStatusCode::isError, clientResponse -> {
System.out.println("WebClient请求异常");
return Mono.error(new RuntimeException("请求异常" + clientResponse.statusCode().value()));
}).build();
HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)).blockTimeout(Duration.ofSeconds(60)).build();
return proxyFactory.createClient(AlbumsService.class);
}
2.单元测试