【Spring MVC】WebClientの導入

概要

RESTなAPIにアクセスするのはRestTemplateではなくWebClientが今後推奨となるため、WebClientの概要についてまとめた。
WebClientを使用するための準備と、どんなメソッドがあるのかを紹介している。

 

前提

今後動作確認を行う際には、以前の記事で作成したREST APIアプリにリクエストを行ってレスポンスを取得する。
※今回のMavenプロジェクトの作成についても、以下をベースとしている

あわせて読みたい

概要 これから数回にかけてREST APIについて学んだことを載せていく。 今回はREST APIの仕組みとプロジェクト作成方法について紹介する。 尚、RESTとは何かということについては取り扱わない。   仕組み[…]

 

WebClient

WebClientは、Spring Framework5以降で導入された非同期・リアクティブなHTTPクライアントとなる。

REST APIや外部サービスとHTTP経由で通信する際に使用し、GET/POST/PUT/DELETE などのHTTPメソッドを柔軟に扱える。
SpringMVCでは一律同期的に処理を行うため、以降の記事では非同期の処理については扱わない

 

基本的な使い方

WebClientでは、以下のようにメソッドチェーンを使用して柔軟にAPI通信を行う。(※GET通信の例)

webClient.get()
.uri(URI情報)
.retrieve()
.bodyToMono(取得したいレスポンスの型)
.block();

 

webClient.get()

GET通信を行うメソッド。(「webClient」は、WebClientのインスタンス)
この段階ではリクエストはまだ実施せず、内部型のWebClient.RequestHeadersUriSpecオブジェクトを返却する。

 

WebClient.RequestHeadersUriSpec.uri(URI情報)

リクエストの URI を設定する。
WebClient.RequestHeadersSpec<?> を返し、ヘッダー設定や送信メソッドが利用可能になる。

 

WebClient.RequestHeadersSpec.retrieve()

リクエストを送信し、レスポンスを扱うWebClient.ResponseSpecを返却する。

 

WebClient.ResponseSpec.bodyToMono(取得したいレスポンスの型)

レスポンスボディを非同期で扱う Mono<取得したい型> を返す。
※上記のメソッドは、レスポンスボディのみ(ステータスやヘッダーは含まない)を扱う

 

Mono.block()

非同期処理が完了するまで待機し、同期的な戻り値として取得する。
Spring MVCでは、基本的にこのメソッドで同期処理に変換する。

 

基本的なメソッド

WebClientは内部型オブジェクトとMonoオブジェクトを使用してAPI通信を行う。
以下にWebClientにてメソッドチェーンで使用する基本的なメソッドを紹介する。

 

メソッド 説明
WebClient.get() GET通信を行う
WebClient.post() POST通信を行う
WebClient.put() PUT通信を行う
WebClient.delete() DELETE通信を行う
UriSpec.uri(URI情報) URI情報を設定する
RequestBodySpec.bodyValue(リクエストボディ) POSTやPUT通信に使用するリクエストボディを設定する
RequestBodySpec.contentType(コンテンツタイプ) Content-Typeヘッダーを設定する
RequestHeadersSpec.headers(ヘッダー情報) リクエストのヘッダー情報を設定
RequestHeadersSpec.retrieve() リクエスト送信を行い、ResponseSpecを取得する
RequestHeadersSpec.exchangeToMono() リクエスト送信を行い、ClientResponseを変換してMono<T>を取得する
※ClientResponseはヘッダー/ステータス/ボディにアクセス可能なオブジェクト
ResponseSpec.bodyToMono(レスポンス型) リクエスト送信を行い、Mono<T>を取得する
Mono<T>.block() 同期的にT型のレスポンスを取得する

 

事前準備

WebClientを使用するための事前準備を行う。

 

必要ライブラリ

WebClientまわりの機能を利用するため、必要な資材をpom.xmlに追加する。

 

pom.xml


<dependencies>
	<!-- Lombok -->
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<version>1.18.30</version>
		<scope>provided</scope>
	</dependency>

	<!-- Spring Web MVC -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>5.3.30</version>
	</dependency>

	<!-- Spring WebFlux -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webflux</artifactId>
		<version>5.3.30</version>
	</dependency>

	<!-- Project Reactor Core -->
	<dependency>
		<groupId>io.projectreactor</groupId>
		<artifactId>reactor-core</artifactId>
		<version>3.4.34</version>
	</dependency>

	<!-- Project Reactor Netty -->
	<dependency>
		<groupId>io.projectreactor.netty</groupId>
		<artifactId>reactor-netty</artifactId>
		<version>1.0.39</version>
	</dependency>

	<!-- SLF4J API -->
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.7.36</version>
	</dependency>

	<!-- Logback Classic -->
	<dependency>
		<groupId>ch.qos.logback</groupId>
		<artifactId>logback-classic</artifactId>
		<version>1.2.11</version>
	</dependency>

	<!-- Jackson Datatype JSR310 for Java Time API -->
	<dependency>
		<groupId>com.fasterxml.jackson.datatype</groupId>
		<artifactId>jackson-datatype-jsr310</artifactId>
		<version>2.15.2</version>
	</dependency>
</dependencies>

 

WebClientを使用するためには以下の資材が必要となる。

・Spring WebFlux: WebClient本体の機能
・Project Reactor Core: Monoオブジェクトなどの機能
・Project Reactor Netty: 非同期HTTP通信の機能 

 

Bean定義

WebClientをDIコンテナから取得するため、Bean定義を行う。
簡潔に記述できるため、Javaベースで作成する。

 

WebClientConfig.java


package com.example.webclient_prototype.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;

import reactor.netty.http.client.HttpClient;

/**
 * WebClientのBean定義
 */
@Configuration
public class WebClientConfig {
	
	@Bean
	public HttpClient httpClient() {
		return HttpClient.create();
	}

	@Bean
	public ReactorClientHttpConnector reactorClientHttpConnector(HttpClient httpClient) {
		return new ReactorClientHttpConnector(httpClient);
	}

	@Bean
	public WebClient webClient(ReactorClientHttpConnector reactorClientHttpConnector) {
		return WebClient.builder()
				.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
				.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE + ", " + MediaType.APPLICATION_PROBLEM_JSON_VALUE)
				.clientConnector(reactorClientHttpConnector)
				.build();
	}
}

 

.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE + “, ” + MediaType.APPLICATION_PROBLEM_JSON_VALUE)

WebClientを使用して行うすべてのHTTPリクエストに、共通のHTTPヘッダーを設定している。

 

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<!-- コンポーネントスキャン -->
	<context:component-scan base-package="com.example.webclient_prototype.biz" />
	<!-- WebClientのBean定義 -->
	<bean class="com.example.webclient_prototype.config.WebClientConfig"/>
</beans>

 

<!– WebClientのBean定義 –>
<bean class=”com.example.webclient_prototype.config.WebClientConfig”/>

定義したJavaベースのBean定義ファイルをDIコンテナに登録する。
※コンポーネントスキャン対象のパッケージ配下に格納していれば不要

 

APIアクセスクラス

WebClientのDIを行い、APIにアクセスするメソッドを今後追加していく。

 

WebApiClient.java


package com.example.webclient_prototype.biz;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

/**
 * WebClientを使用したAPI疎通クラス
 */
@Component
public class WebApiClient {

	@Autowired
	private WebClient webClient;
	
}

 

リソースクラス

REST APIアプリから返却されるレスポンスを、リソースクラスにマッピングするため用意する。

 

Resource.java


package com.example.webclient_prototype.resource;


import java.time.LocalDate;

import com.fasterxml.jackson.annotation.JsonFormat;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * リソースクラス
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Resource {
	/** ID */
	private String id;
	/** 名前 */
	private String name;
	/** とある日付 */
	@JsonFormat(pattern = "yyyy-MM-dd")
	private LocalDate hogeDate;
}

 

動作確認用クラス

WebClientの動作を簡易的に確認するため、エントリーポイントとなるクラスを用意する。

 

Main.java


package com.example.webclient_prototype.executor;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.example.webclient_prototype.biz.WebApiClient;

public class Main {

	public static void main(String[] args) {
		try (var context = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml")) {
			// DIコンテナから取得
			var client = context.getBean(WebApiClient.class);
			
		}
	}

}

 

 

まとめ

 

☑ RestTemplateは今後機能追加がないため、WebClientの使用が推奨される

☑ WebClientはメソッドチェーンで柔軟なAPI通信を実装できる

☑ SpringMVC環境では、 WebClientを同期的に使用する

スポンサーリンク