前言
Spring 框架中,常用的发送 Http、Https请求的有 RestTemplate
,WebFlux
中的WebClient
。
本文主要说一下 WebClient的基本使用。
主要原因及场景如下:
在一个类似监听机器的项目中,需要发送警告到某群聊。
这种警告可能会堆积,需要异步发送出去。
官方文档如下:
https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#boot-features-webflux
中文版如下:
https://www.cnblogs.com/jmcui/p/11775217.html
在SpringBoot中使用
1、引入依赖
<!-- webclient config-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、添加配置类
package com.huice.order.ops.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import java.util.concurrent.TimeUnit;
/**
* 配置 WebFlux,配置WebClient。
*
* @date: 2021/11/2 15:45
* @see WebClient
*/
@Configuration
public class WebClientConfig {
/**
* URLConnection's connect timeout (in milliseconds).
*/
@Value("${http.client.connect-timeout:3000}")
Integer connectTimeout;
/**
* URLConnection's read timeout (in milliseconds).
*/
@Value("${http.client.read-timeout:3000}")
Integer readTimeout;
/**
* URLConnection's write timeout (in milliseconds).
*/
@Value("${http.client.write-timeout:3000}")
Integer writeTimeout;
/**
* 注入 WebClient
*
* @param objectMapper ObjectMapper实例
* @return WebClient 实例
* @see WebClient
*/
@Bean("webClient")
public WebClient webClient(ObjectMapper objectMapper) {
HttpClient httpClient = HttpClient.create().tcpConfiguration(client -> client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout)
.doOnConnected(
conn -> conn.addHandlerLast(new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS))
.addHandlerLast(new WriteTimeoutHandler(writeTimeout, TimeUnit.MILLISECONDS))));
ExchangeStrategies strategies = ExchangeStrategies
.builder()
.codecs((ClientCodecConfigurer clientDefaultCodecsConfigurer) -> {
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
}).build();
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).exchangeStrategies(strategies).build();
}
@Bean
public ObjectMapper objectMapper(){
return new ObjectMapper();
}
}
3、使用
// 注入 webclient
@Resource
private WebClient webClient;
@Value("请求的url")
private String url;
// 请求体
Map<String, Object> params = new HashMap<>(16);
// webclient发送请求
webClient.method(HttpMethod.POST).uri(url).bodyValue(params).retrieve()
// 转换返回结果:这个可以自己定义,需要有空构造器的bean即可。
.bodyToMono(String.class)
// 请求成功后的响应
.doOnNext(resp -> log.debug("发送告警消息 [{}]", resp))
// 发生错误
.doOnError(throwable -> log.error(throwable.getLocalizedMessage()))
// 异步消费;同步时使用blockOptional()即可
.subscribe();