SOAP Web サービスの生成

このガイドでは、Spring を使用して SOAP ベースの Web サービスサーバーを作成するプロセスについて説明します。

構築するもの

WSDL ベースの SOAP Web サービスを使用して、ヨーロッパのさまざまな国からのデータを公開するサーバーを構築します。

この例を単純化するために、英国、スペイン、ポーランドのハードコードされたデータを使用します。

必要なもの

本ガイドの完成までの流れ

ほとんどの Spring 入門ガイドと同様に、最初から始めて各ステップを完了するか、すでに慣れている場合は基本的なセットアップステップをバイパスできます。いずれにしても、最終的に動作するコードになります。

最初から始めるには、Spring Initializr から開始に進みます。

基本スキップするには、次の手順を実行します。

完了したときは、gs-soap-service/complete のコードに対して結果を確認できます。

Spring Initializr から開始

IDE を使用する場合はプロジェクト作成ウィザードを使用します。IDE を使用せずにコマンドラインなどで開発する場合は、この事前に初期化されたプロジェクトからプロジェクトを ZIP ファイルとしてダウンロードできます。このプロジェクトは、このチュートリアルの例に合うように構成されています。

プロジェクトを手動で初期化するには:

  1. IDE のメニューまたはブラウザーから Spring Initializr を開きます。アプリケーションに必要なすべての依存関係を取り込み、ほとんどのセットアップを行います。

  2. Gradle または Maven のいずれかと、使用する言語を選択します。このガイドは、Java を選択したことを前提としています。

  3. 依存関係をクリックして、Spring Web Services を選択します。

  4. 生成をクリックします。

  5. 結果の ZIP ファイルをダウンロードします。これは、選択して構成された Web アプリケーションのアーカイブです。

EclipseIntelliJ のような IDE は新規プロジェクト作成ウィザードから Spring Initializr の機能が使用できるため、手動での ZIP ファイルのダウンロードやインポートは不要です。

WSDL ランタイム依存関係を追加する

サービスは実行時に wsdl4j 依存関係を必要とするため、これを Gradle ビルドに追加しましょう。

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-webservices'
	runtimeOnly 'wsdl4j:wsdl4j'
	testImplementation 'org.springframework.boot:spring-boot-starter-webservices-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

または POM ファイル:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-webservices</artifactId>
	</dependency>
	<dependency>
		<groupId>wsdl4j</groupId>
		<artifactId>wsdl4j</artifactId>
		<optional>true</optional>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-webservices-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

ドメインを定義する XML スキーマを作成する

Web サービスドメインは、Spring-WS が WSDL として自動的にエクスポートする XML スキーマファイル(XSD)で定義されます。

国の namepopulationcapitalcurrency を返す操作を含む XSD ファイルを作成します。次のリスト(src/main/resources/META-INF/schemas/countriesWs.xsd から)は、必要な XSD ファイルを示しています。

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="https://spring.io/guides/gs-producing-web-service"
           targetNamespace="https://spring.io/guides/gs-producing-web-service" elementFormDefault="qualified">

    <xs:element name="getCountryRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCountryResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="country" type="tns:country"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="country">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="population" type="xs:int"/>
            <xs:element name="capital" type="xs:string"/>
            <xs:element name="currency" type="tns:currency"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="currency">
        <xs:restriction base="xs:string">
            <xs:enumeration value="GBP"/>
            <xs:enumeration value="EUR"/>
            <xs:enumeration value="PLN"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

XML スキーマに基づいてドメインクラスを生成する

次のステップは、XSD ファイルから Java クラスを生成することです。適切なアプローチは、Maven または Gradle プラグインを使用して、ビルド時にこれを自動的に行うことです。

以下のリストは、Maven に必要なプラグイン構成を示しています。

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>jaxb2-maven-plugin</artifactId>
	<version>4.0.0</version>
	<executions>
		<execution>
			<id>xjc</id>
			<goals>
				<goal>xjc</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<sources>
			<source>${project.basedir}/src/main/resources/META-INF/schemas/countriesWs.xsd</source>
		</sources>
	</configuration>
</plugin>

生成されたクラスは、target/generated-sources/jaxb/ ディレクトリに配置されます。

Gradle で同じことを行うには、plugin セクションで新しいプラグインを宣言します。

id 'com.github.bjornvester.xjc' version '1.9.0'

次に、XSD ファイルの場所を指すように構成します。

xjc {
	xsdDir.set(layout.projectDirectory.dir("src/main/resources/META-INF/schemas"))
}

どちらの場合も、JAXB ドメインオブジェクト生成プロセスはビルドツールのライフサイクルに組み込まれているため、追加の手順は必要ありません。

カントリーリポジトリの作成

Web サービスにデータを提供するには、国のリポジトリを作成します。このガイドでは、ハードコードされたデータを使用してダミーの国リポジトリの実装を作成します。次のリスト(src/main/java/com/example/producingwebservice/CountryRepository.java から)は、その方法を示しています。

package com.example.producingwebservice;

import java.util.HashMap;
import java.util.Map;

import io.spring.guides.gs_producing_web_service.Country;
import io.spring.guides.gs_producing_web_service.Currency;

import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

@Component
public class CountryRepository {

	private static final Map<String, Country> countries = new HashMap<>();

	static {
		Country spain = new Country();
		spain.setName("Spain");
		spain.setCapital("Madrid");
		spain.setCurrency(Currency.EUR);
		spain.setPopulation(46704314);

		countries.put(spain.getName(), spain);

		Country poland = new Country();
		poland.setName("Poland");
		poland.setCapital("Warsaw");
		poland.setCurrency(Currency.PLN);
		poland.setPopulation(38186860);

		countries.put(poland.getName(), poland);

		Country uk = new Country();
		uk.setName("United Kingdom");
		uk.setCapital("London");
		uk.setCurrency(Currency.GBP);
		uk.setPopulation(63705000);

		countries.put(uk.getName(), uk);
	}

	public Country findCountry(String name) {
		Assert.notNull(name, "The country's name must not be null");
		return countries.get(name);
	}
}

カントリーサービスエンドポイントの作成

サービスエンドポイントを作成するには、いくつかの Spring WS アノテーションを持つ POJO だけで、受信 SOAP リクエストを処理する必要があります。次のリスト(src/main/java/com/example/producingwebservice/CountryEndpoint.java から)は、そのようなクラスを示しています。

package com.example.producingwebservice;

import io.spring.guides.gs_producing_web_service.GetCountryRequest;
import io.spring.guides.gs_producing_web_service.GetCountryResponse;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

@Endpoint
public class CountryEndpoint {

	private static final String NAMESPACE_URI = "https://spring.io/guides/gs-producing-web-service";

	private final CountryRepository countryRepository;

	public CountryEndpoint(CountryRepository countryRepository) {
		this.countryRepository = countryRepository;
	}

	@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
	@ResponsePayload
	public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
		GetCountryResponse response = new GetCountryResponse();
		response.setCountry(countryRepository.findCountry(request.getName()));

		return response;
	}
}

@Endpoint アノテーションは、受信 SOAP メッセージを処理するための潜在的な候補として、クラスを Spring WS に登録します。

次に、@PayloadRoot アノテーションは、メッセージの namespace と localPart に基づいて、Spring WS によってハンドラーメソッドを選択するために使用されます。

@RequestPayload アノテーションは、受信メッセージがメソッドの request パラメーターにマッピングされることを示します。

@ResponsePayload アノテーションにより、Spring WS は返された値をレスポンスペイロードにマップします。

これらすべてのコードチャンクで、WSDL に基づいてドメインクラスを生成するタスクを実行しない限り、io.spring.guides クラスは IDE でコンパイル時エラーを報告します。

Web サービスを公開する

次に、クライアントが WSDL 定義を取得できるようにサービスを公開する必要があります。Spring Boot は、設定された場所にあるすべての ".xsd" と " .wsdl" ファイルをスキャンします。まず、src/main/resources/application.properties を編集してスキーマファイルの場所を宣言する必要があります。

spring.webservices.wsdl-locations=classpath:META-INF/schemas/

Spring Boot は、ファイル名と一致する名前を持つ SimpleXsdSchema または DefaultWsdl11Definition の Bean を作成します。ここでは、countriesWs という名前の SimpleXsdSchema Bean が期待されており、これを使用して WSDL Bean を作成して公開できます。そのために、以下の内容の新しい src/main/java/com/example/producingwebservice/WebServiceConfig.java ファイルを作成しましょう。

package com.example.producingwebservice;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;

@Configuration(proxyBeanMethods = false)
public class WebServiceConfig {

	@Bean
	public DefaultWsdl11Definition countries(SimpleXsdSchema countriesWs) {
		DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
		wsdl11Definition.setPortTypeName("CountriesPort");
		wsdl11Definition.setLocationUri("/services");
		wsdl11Definition.setTargetNamespace("https://spring.io/guides/gs-producing-web-service");
		wsdl11Definition.setSchema(countriesWs);
		return wsdl11Definition;
	}

}

DefaultWsdl11Definition は、構成された XsdSchema を使用して標準 WSDL 1.1 を公開します。

DefaultWsdl11Definition の Bean という名前は、生成された WSDL ファイルが利用できる URL を決定します。この場合、WSDL は http://<host>:<port>/services/countries.wsdl (英語) で利用できます。

デフォルトでは、"/services" HTTP エンドポイントで公開されますが、これは spring.webservices.path プロパティを使用してカスタマイズできます。

アプリケーションをテストする

アプリケーションが実行されたため、テストできます。次の SOAP リクエストを含む request.xml というファイルを作成します。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
				  xmlns:gs="https://spring.io/guides/gs-producing-web-service">
   <soapenv:Header/>
   <soapenv:Body>
      <gs:getCountryRequest>
         <gs:name>Spain</gs:name>
      </gs:getCountryRequest>
   </soapenv:Body>
</soapenv:Envelope>

SOAP インターフェースのテストに関しては、いくつかのオプションがあります。*nix/Mac システムを使用している場合は、SoapUI (英語) に似たものを使用するか、コマンドラインツールを使用できます。次の例では、コマンドラインから curl を使用しています。

# Use data from file
$ curl --header "Content-Type: text/xml" -d @request.xml http://localhost:8080/services | xmllint --format

その結果、次のレスポンスが表示されます。

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <ns2:getCountryResponse xmlns:ns2="https://spring.io/guides/gs-producing-web-service">
      <ns2:country>
        <ns2:name>Spain</ns2:name>
        <ns2:population>46704314</ns2:population>
        <ns2:capital>Madrid</ns2:capital>
        <ns2:currency>EUR</ns2:currency>
      </ns2:country>
    </ns2:getCountryResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

要約

おめでとう! Spring Web Services を使用して SOAP ベースのサービスを開発しました。

関連事項

次のガイドも役立つかもしれません:

新しいガイドを作成したり、既存のガイドに貢献したいですか? 投稿ガイドラインを参照してください [GitHub] (英語)

すべてのガイドは、コード用の ASLv2 ライセンス、およびドキュメント用の帰属、NoDerivatives クリエイティブコモンズライセンス (英語) でリリースされています。

コードを入手する