2
1

More than 3 years have passed since last update.

【Spring Boot】SOAPクライアントの実装

Last updated at Posted at 2021-03-28

はじめに

SpringBootでのSOAPクライアント実装方法について記載します。
あまり使われなくなったSOAPですが、たまに使うので備忘として。

環境

  • Spring Boot 2.3
  • spring-ws-core
  • Java 8

ライブラリの追加

spring-ws-coreを依存関係に追加します。

pom.xm
<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-ws-core</artifactId>
</dependency>

WSDLからソース生成

maven-jaxb2-pluginを使用します。
pom.xmlに下記を定義し、実行することでSOAPサービスのRequest/ResponseのBeanが生成されます。
データ定義をXSDに切り出している場合にも対応しています。

#Gradle版がなくすみません…。いつか試して追記したいです。

pom.xml
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    <!-- WSDLからJAXBのソースを生成するためのプラグイン -->
    <plugin>
      <groupId>org.jvnet.jaxb2.maven2</groupId>
      <artifactId>maven-jaxb2-plugin</artifactId>
      <version>0.14.0</version>
      <executions>
        <!-- 以下、webサービスごとに定義 -->
        <execution>
          <id>サービスのID(任意の値)executions内で一意</id>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <!-- WSDLから生成する旨の宣言 -->
            <schemaLanguage>WSDL</schemaLanguage>
            <!-- 生成元となるWSDLとXSDの格納先 ※WSDLとXSDで同一ディレクトリ前提 -->
            <schemaDirectory>${project.basedir}/wsdl/exampleSoap</schemaDirectory>
            <!-- WSDLからXSDを参照している場合に必要となるスキーマ参照定義 -->
            <schemaIncludes>
              <include>exampleSoap.wsdl</include>
            </schemaIncludes>
            <!-- ソース生成先パッケージ -->
            <generatePackage>exampleSoap.api.client.exampleSoap.dto</generatePackage>
            <!-- ソース生成先ディレクトリ -->
            <generateDirectory>${project.basedir}/src/main/java</generateDirectory>
            <!-- 生成するソースのgenerateコメントにタイムスタンプを設定しないようにする(true:設定しない) -->
            <noFileHeader>true</noFileHeader>
            <!-- 生成後のディレクトリ削除要否(false:削除しない) -->
            <clearOutputDir>false</clearOutputDir>
            <!-- episodeファイル生成要否(false:生成しない) ※デフォルトはtrueなので抑止 -->
            <episode>false</episode>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

SOAPクライアントクラスの作成

WebServiceGatewaySupportを継承したクラスを作成します。
marshalSendAndReceiveでSOAP通信を実行しています。

リクエストのBeanのインスタンスはObjectFactoryで生成します。ObjectFactoryはWSDLからのソース生成時にBeanと一緒に生成されます。

@Service
public class ExampleSoapClientService extends WebServiceGatewaySupport {

    @SuppressWarnings("unchecked")
    public ExampleSoapResponse execute() throws WebServiceException {
        // RequestのBean作成
        ObjectFactory objectFactory = new ObjectFactory();
        ExampleSoapRequest reqBean = objectFactory.createExampleSoapRequest();
        reqBean.setUserId("user0001");
        reqBean.setName("サンプル太郎"); 
        reqBean.setAge("25"); 
        // ...省略
        // 作成したリクエストのBeanをJAXBElementにラップする
        JAXBElement<ExampleSoapRequest> request = objectFactory.createExampleSoap(reqBean);

        JAXBElement<ExampleSoapResponse> response = null;
        // SOAP通信実行
        try {
            response = (JAXBElement<ExampleSoapResponse>) getWebServiceTemplate().marshalSendAndReceive(request);
        } catch ( SoapFaultClientException e ) {
            // Faultエラーが返ってきた場合の処理
            // e.getSoapFault().getFaultDetail()でFault電文の<detail>タグ内の情報を取得できる
        } catch ( WebServiceException e ) {
            // その他のSOAP通信エラーが発生した場合の処理
        }
        return response.getValue(); // getValue()でResponseのルート要素のBeanを取得
    }
}

※補足
説明と関係無いため省略していますが、クラス内で@Value@Autowiredを使っているためサービスクラス(@Service)として作成しています。
他のコンポーネントをDIする必要がなければこのクラス自体はSpringアノテーションはつけず、後述のConfigクラスでBean定義する形がSpring公式のサンプルにも則っているので綺麗だと思います。

JAXBマーシャラのBean定義とSOAPクライアントクラスの設定

JAXBマーシャラをBean定義し、先ほど作成したSOAPクライアントクラスへ設定します。
エンドポイントの設定もここで行っています。

※今回呼出すSOAPサービスはBasic認証があるため下記サンプル内でBasic認証に関する設定もしていますが、認証なしの場合は不要です。

SOAPクライアントクラスをサービスクラス(@Service)で作成した場合
@Configuration
public class SoapClientConfig {

    /** SOAPエンドポイント */
    @Value("${exampleSoap.endpointUri}")
    private String exampleSoapEndpointUri;

    /** Basic認証情報 ※認証なしの場合は不要 */
    @Value("${exampleSoap.basicAuthPassword")
    private String basicAuthPass;

    /** SOAPクライアントクラス(WebServiceGatewaySupportのサブクラス) */
    @Autowired
    private ExampleSoapClientService exampleSoapClientService;

    /** JAXBマーシャラのBean定義 */
    @Bean
    public Jaxb2Marshaller exampleSoapMarshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        // SoapのBean格納パッケージを指定
        // 可変長引数なのでアプリケーション内で複数のSOAPサービスを呼出す場合はカンマ区切りで指定
        marshaller.setPackagesToScan("exampleSoap.api.client.exampleSoap.dto");

        // SOAPクライアントクラスの設定
        exampleSoapClientService.setMarshaller(marshaller); // マーシャラの設定
        exampleSoapClientService.setUnmarshaller(marshaller); // アンマーシャラの設定
        exampleSoapClientService.setDefaultUri(exampleSoapEndpointUri); // エンドポイントの設定
        // Basic認証をする場合の設定 ※認証なしの場合は不要
        exampleSoapClientService.getWebServiceTemplate().setMessageSender(new HttpUrlConnectionMessageSender() {
            @Override
            protected void prepareConnection(HttpURLConnection connection) throws IOException {
                // パスワードをBase64エンコードしてリクエストヘッダに追加する
                String password = basicAuthPass;
                String encodedPass = Base64.getEncoder().encodeToString(password.getBytes());
                connection.setRequestProperty("Authorization", "Basic" + encodedPass);
                super.prepareConnection(connection);
            }
        });
        return marshaller;
    }
}
SOAPクライアントクラスをSpringアノテーションをつけずに作成した場合
@Configuration
public class SoapClientConfig {

    /** SOAPエンドポイント */
    @Value("${exampleSoap.endpointUri}")
    private String exampleSoapEndpointUri;

    /** Basic認証情報 ※認証なしの場合は不要 */
    @Value("${exampleSoap.basicAuthPassword")
    private String basicAuthPass;

    /** JAXBマーシャラのBean定義 */
    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        // SoapのBean格納パッケージを指定
        // 可変長引数なのでアプリケーション内で複数のSOAPサービスを呼出す場合はカンマ区切りで指定
        marshaller.setPackagesToScan("exampleSoap.api.client.exampleSoap.dto");        
        return marshaller;
    }

    /** SOAPクライアントクラスのBean定義 */
    @Bean
    public ExampleSoapClientService exampleSoapClientService (Jaxb2Marshaller marshaller) {
        ExampleSoapClientService exampleSoapClientService = new ExampleSoapClientService();
        // SOAPクライアントクラスの設定
        exampleSoapClientService.setMarshaller(marshaller); // マーシャラの設定
        exampleSoapClientService.setUnmarshaller(marshaller); // アンマーシャラの設定
        exampleSoapClientService.setDefaultUri(exampleSoapEndpointUri); // エンドポイントの設定
        // Basic認証をする場合の設定 ※認証なしの場合は不要
        exampleSoapClientService.getWebServiceTemplate().setMessageSender(new HttpUrlConnectionMessageSender() {
            @Override
            protected void prepareConnection(HttpURLConnection connection) throws IOException {
                // パスワードをBase64エンコードしてリクエストヘッダに追加する
                String password = basicAuthPass;
                String encodedPass = Base64.getEncoder().encodeToString(password.getBytes());
                connection.setRequestProperty("Authorization", "Basic" + encodedPass);
                super.prepareConnection(connection);
            }
        });
        return exampleSoapClientService;
    }
}

リクエスト/レスポンス電文をログ出力する

application.ymlに以下を定義することで出力されます。

application.yml
logging:
  level:
    org.springframework.ws.client.MessageTracing.sent: TRACE
    org.springframework.ws.client.MessageTracing.received: TRACE

参考

Spring公式: SOAP Web サービスの使用

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1