Introduction to the

WebClient is a new non-blocking, reactive HttpClient framework introduced in Spring5.

WebClient has the following advantages over traditional RestTemplate:

  • Non-blocking I/O.
  • Reaction flow back pressure.
  • High concurrency, less hardware resource consumption.
  • Smooth API design.
  • Synchronous and asynchronous interactions.
  • Streaming support

use

1. Create webclient

 WebClient.builder()
                .clientConnector(new JettyClientHttpConnector())
                .baseUrl(baseUrl)
                .filter(logRequest())
                .exchangeStrategies(ExchangeStrategies.builder()
                        .codecs(clientCodecConfigurer -> clientCodecConfigurer.defaultCodecs()
                                .maxInMemorySize(16 * 1024 * 1024))
                        .build())
                .build();
Copy the code

ClientConnector: Client connection implementation. By default, Netty is used. There is also a built-in implementation of Jetty, but you can also customize the clientConnector interface to define new underlying libraries.

public interface ClientHttpConnector { /** * Connect to the origin server using the given {@code HttpMethod} and * {@code URI} and apply the given {@code requestCallback} when the HTTP * request of the underlying API can be initialized  and written to. * @param method the HTTP request method * @param uri the HTTP request URI * @param requestCallback a function that prepares and writes to the request, * returning a publisher that signals when it's done writing. * Implementations can return a {@code Mono<Void>} by calling * {@link ClientHttpRequest#writeWith} or {@link ClientHttpRequest#setComplete}. * @return publisher for the {@link ClientHttpResponse} */ Mono<ClientHttpResponse> connect(HttpMethod method, URI uri, Function<? super ClientHttpRequest, Mono<Void>> requestCallback); }Copy the code

BaseUrl: configures a baseUrl for the request, usually used to configure the domain name.

Filter: You can configure multiple filters. The commonly used filters include before and after a request, permission verification, and logging.

// Before the request, Private ExchangeFilterFunction logRequest() {return (clientRequest, next) -> {log.info("Request: {} {}", clientRequest.method(), clientRequest.url()); clientRequest.headers() .forEach((name, values) -> values.forEach(value -> log.info("Request: {}={}", name, value))); return next.exchange(clientRequest); }; }Copy the code

Exchange Strategies: Configure the Exchange that needs to be used. This is primarily a reconfiguration of the memory available for parsing the response, since the default size is only 32K and the return value for any request is exceeded, so this needs to be resized. Of course, this method can also set other configuration, details can see the documentation

2. Use

The GET method

webClient.get() .uri(url, (Object[]) param) .accept(mediaType) .exchangeToMono(response -> { if (response.statusCode().equals(HttpStatus.OK)) { return response.bodyToMono(tClass).doOnNext(item -> { log.info("Get Response :{}", JSONObject.toJSONString(item)); }); } else { return Mono.error(new ServerException(ResponseCode.API_ERROR)); }});Copy the code

The uri has two parameters. The first is the address of the request, and the second is the request parameter. In this case, the parameter is the path variable, similar to the REST style, but there are other ways to write it.

1.
webClient.get().uri(uriBuilder -> uriBuilder.path("/user/{id}/{name}")
                            .build(id, name));
2.                           
Map<String, Object> uriVariables = new HashMap<>();
uriVariables.put("id", "id1");
uriVariables.put("name", "name1");                        
webClient.get().uri("/user/{id}/{name}", uriVariables)
                                                 
Copy the code

Accept is the contentType that sets the request, and the built-in MediaType class has a defined constant direct reference interface

public static final MediaType APPLICATION_JSON;

public static final String APPLICATION_JSON_VALUE = "application/json";
Copy the code

The processing of the response results is in exchangeToMono, where you can write your own business logic.

POST method

// A jsonPost request webclient.post ().uri(expand).contentType(MediaType.application_json) .body(Mono.just(ParamsUtil.ObjectToMap(body)), Map.class) .exchangeToMono(clientResponse -> { MediaType mediaType = clientResponse.headers().contentType().orElse(MediaType.APPLICATION_JSON); log.info("PostJson resp headers :{},statusCode:{}", mediaType, clientResponse.statusCode()); if (clientResponse.statusCode().equals(HttpStatus.OK)) { return clientResponse.bodyToMono(String.class).doOnNext(item ->  { log.debug("PostJson Response :{}", JSONObject.toJSONString(item)); }).flatMap(str -> Mono.just(JSONObject.parseObject(str, tClass))); } else { return clientResponse.bodyToMono(String.class).doOnNext(item -> { log.info("PostJson Response :{}", JSONObject.toJSONString(item)); }).flatMap(item -> Mono.error(new ServerException(ResponseCode.API_ERROR))); }});Copy the code

The post method is similar to the GET method, but the difference is that the parameters are passed. In the POST method, you need to put the parameters in the body, which is wrapped in mono, and you can support any data type. It can be a Java object or a Map