Java
SOAP
spring

Spring WS(WebService)でSOAPリクエストを受け取るための設定

More than 1 year has passed since last update.

Spring WS (WebService)を使ったSOAPで死ぬほどハマったのでまとめておきます。


Spring WS (2.2.2)でSOAPリクエストを受け取る環境をつくる。
以下のような構成の既存WEBアプリケーションへの組込みです。

  • Spring Framework 3.2.8
  • Spring MVC
  • Java7
  • Tomcat7

pom.xml

依存関係を追加

<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-ws-core</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

web.xml

{context-root}/ws/* のアクセスがMessageDispatcherServletに流れるようになる。

<servlet>
  <servlet-name>spring-ws</servlet-name>
  <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/META-INF/spring-ws-servlet.xml</param-value>
  </init-param>
  <init-param>
    <param-name>transformWsdlLocations</param-name>
    <param-value>true</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>spring-ws</servlet-name>
  <url-pattern>/ws/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>spring-ws</servlet-name>
  <url-pattern>*.wsdl</url-pattern>
</servlet-mapping>

spring-ws-servlet.xml

WEB-INF配下にwsdlファイルを配備しておく

<?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:sws="http://www.springframework.org/schema/web-services"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                      http://www.springframework.org/schema/web-services
                      http://www.springframework.org/schema/web-services/web-services-2.0.xsd
                      http://www.springframework.org/schema/context
                      http://www.springframework.org/schema/context/spring-context-3.2.xsd">

  <context:component-scan base-package="jp.xxx.*" />
  <sws:annotation-driven />
  <sws:static-wsdl id="hoge" location="/WEB-INF/hoge.wsdl"/>
</beans>

wsdl/xsdからjavaクラスを生成

wsdl/xsdが用意できる場合は便利。

mavenを利用し、pom.xml に以下を記述する。

  • wsdlの場合

WEB-INF配下のwsdlファイル参照を想定

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxb2-maven-plugin</artifactId>
  <version>1.6</version>
  <executions>
    <execution>
      <id>xjc</id>
      <goals>
        <goal>xjc</goal>
      </goals>
    </execution>
  <configuration>
  <wsdl>true</wsdl>
  <xmlschema>false</xmlschema>
  <schemaDirectory>${basedir}/src/main/webapp/WEB-INF</schemaDirectory>
  <schemaFiles>hoge.wsdl</schemaFiles>
  <outputDirectory>${basedir}/src/main/java</outputDirectory>
  <clearOutputDir>false</clearOutputDir>
  </configuration>
</plugin>
  • xsdの場合

resource配下のxsdファイルの参照を想定

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxb2-maven-plugin</artifactId>
  <version>1.6</version>
  <executions>
    <execution>
      <id>xjc</id>
      <goals>
        <goal>xjc</goal>
      </goals>
    </execution>
    <configuration>
      <schemaDirectory>${basedir}/src/main/resource/xsd</schemaDirectory>
      <outputDirectory>${basedir}/src/main/java</outputDirectory>
      <clearOutputDir>false</clearOutputDir>
    </configuration>
</plugin>

mavenでタスク clean jaxb2:xjc を実行すると、wsdl/xsd の記述に基づいて
${basedir}/src/main/java配下にjavaソースが出力される。

(IDEの機能でも同じことができるかも。)

Endpointの作成

spring-ws-servlet.xmlに記載した
component-scanの対象パッケージに作成する。
HogeRequest/HogeResponseが上述のmavenタスクで自動生成されたクラス。

@Endpoint
public class HogeEndPoint {
    private static final String NAMESPACE_URI = "http://example.com/"; // wsdlのtargetNamespaceとあわせる

    @PayloadRoot(localPart = "Hoge", namespace = NAMESPACE_URI)
    @ResponsePayload
    public JAXBElement<HogeResponse> hoge(@RequestPayload JAXBElement<HogeRequest> request) {
        return new JAXBElement<>(
                new QName(NAMESPACE_URI, "HogeResponse"),
                HogeResponse.class,
                new HogeResponse()
        );
    }
}

@RequestPayload 内のフィールドをunmarshal

@RequestPayloadxs:anyType を Object型で受け取った場合、
そこからさらにunmarshalする場合は以下手順でいけた。

Node node = (Node)request.getValue().getPiyo();

JAXBContext jaxb = JAXBContext.newInstance(Piyo.class);
JAXBElement<Piyo> piyo = jaxb.createBinder().unmarshal(node.getFirstChild(), Piyo.class);

ログ出力

logbackを利用していますが、
ログの出力レベルをtraceまで許可してやると、

  • どこまでSOAPリクエストが届いてるのか?
  • EndPointがちゃんとマッピングされてるのか?

などの情報も確認できるため、トラぶったときにはオススメ。



まとめてみると大した記述量でもないですね・・・

ほとんどRESTでしか通信することが無かったので、
SOAP自体への理解度が低いということに気付いた今日この頃。