Apache-cxf-with-wsdl-first

提供:Dev Guides
移動先:案内検索

WSDLを使用したApache CXF

開発したCXF-POJOアプリケーションにより、クライアントとサーバーが非常に緊密に結合されます。 また、サービスインターフェイスへの直接アクセスを許可すると、深刻なセキュリティ上の脅威になります。 そのため、通常、クライアントとサーバー間の分離が望まれます。これは、WSDL(Webサービス記述言語)を使用して実現されます。

XMLベースのWSDLドキュメントでWebサービスインターフェイスを記述します。 ツールを使用して、このWSDLをApache CXFインターフェースにマップし、クライアントおよびサーバーアプリケーションで実装および使用します。 デカップリングを提供するには、WSDLから開始することが好ましい方法です。 このためには、最初に新しい言語であるWSDLを学ぶ必要があります。 WSDLの作成には慎重なアプローチが必要であり、作業を開始する前にこれについてある程度理解しておくとよいでしょう。

このレッスンでは、WSDLドキュメントでWebサービスインターフェイスを定義することから始めます。 CXFを使用して、WSDLで始まるサーバーアプリケーションとクライアントアプリケーションの両方を作成する方法を学習します。 CXFの使用に重点を置いて、アプリケーションをシンプルに保ちます。 サーバーアプリケーションが作成されたら、組み込みのCXFクラスを使用して目的のURLに公開します。

最初に、使用するWSDLについて説明しましょう。

HelloWorldのWSDL

実装するWebサービスには、 greetings という1つのWebメソッドがあります。このメソッドは、ユーザー名を保持する string パラメーターを受け入れ、ユーザー名に挨拶メッセージを追加した後、呼び出し元に文字列メッセージを返します。 完全なWSDLは以下に示されています-

//Hello.wsdl
<?xml version = "1.0" encoding = "UTF-8"?>
<wsdl:definitions xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns = "http://helloworld.finddevguides.com/"
   xmlns:wsdl = "http://schemas.xmlsoap.org/wsdl/"
   xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
   name = "HelloWorld"
   targetNamespace = "http://helloworld.finddevguides.com/">
   <wsdl:types>
      <xsd:schema attributeFormDefault = "unqualified"
         elementFormDefault = "qualified"
         targetNamespace = "http://helloworld.finddevguides.com/">
         <xsd:element name = "greetings" type = "tns:greetings"/>
         <xsd:complexType name = "greetings">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "arg0" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
         <xsd:element name = "greetingsResponse"
         type = "tns:greetingsResponse"/>
         <xsd:complexType name = "greetingsResponse">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "return" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
      </xsd:schema>
   </wsdl:types>
   <wsdl:message name = "greetings">
      <wsdl:part element = "tns:greetings" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:message name = "greetingsResponse">
      <wsdl:part element = "tns:greetingsResponse" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:portType name = "HelloWorldPortType">
      <wsdl:operation name = "greetings">
         <wsdl:input message = "tns:greetings" name = "greetings">  </wsdl:input>
         <wsdl:output message = "tns:greetingsResponse" name = "greetingsResponse">
         </wsdl:output>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name = "HelloWorldSoapBinding" type = "tns:HelloWorldPortType">
      <soap:binding style = "document"
      transport = "http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name = "greetings">
         <soap:operation soapAction = "" style = "document"/>
         <wsdl:input name = "greetings"></wsdl:input>
         <wsdl:output name = "greetingsResponse">
            <soap:body use = "literal"/>
         </wsdl:output>
         </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name = "HelloWorldService">
      <wsdl:port binding = "tns:HelloWorldSoapBinding" name = "HelloWorldPort">
         <soap:address location = "http://localhost:9090/HelloServerPort"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

構文的に正しいwsdlを記述することは、開発者にとって常に課題でした。多くのツールがあり、wsdlを作成するためのオンラインエディターが利用できます。 これらのエディターは、実装するメッセージの名前と、メッセージで渡すパラメーター、およびクライアントアプリケーションで受信する戻りメッセージのタイプを要求します。 wsdl構文を知っている場合は、ドキュメント全体を手作業でコーディングするか、エディターの1つを使用して独自のエディターを作成できます。

上記のwsdlでは、 greetings という単一のメッセージを定義しています。 メッセージは、* http://localhost:9090/HelloServerPort。で実行されている *HelloWorldService というサービスに配信されます。

これにより、サーバー開発に進みます。 サーバーを開発する前に、WebサービスへのApache CXFインターフェイスを生成する必要があります。 これは、指定されたwsdlから実行されます。 これを行うには、 wsdl2java というツールを使用します。

wsdl2javaプラグイン

mavenを使用してプロジェクトをビルドするため、 pom.xml ファイルに次のプラグインを追加する必要があります。

<plugins>
   <plugin>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-codegen-plugin</artifactId>
      <version>3.3.0</version>
      <executions>
         <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
               <wsdlOptions>
                  <wsdlOption>
                     <wsdl>src/main/resources/hello.wsdl</wsdl>
                     <faultSerialVersionUID> 1 </faultSerialVersionUID>
                  </wsdlOption>
               </wsdlOptions>
            </configuration>
            <goals>
               <goal>wsdl2java</goal>
            </goals>
         </execution>
      </executions>
   </plugin>
</plugins>
*wsdl* ファイルの場所を *src/main/resources/Hello.wsdl* として指定していることに注意してください。 プロジェクトに適切なディレクトリ構造を作成し、前述の *hello.wsdl* ファイルを指定したフォルダーに追加することを確認する必要があります。
*wsdl2java* プラグインは、このwsdlをコンパイルし、事前定義されたフォルダーにApache CXFクラスを作成します。 完全なプロジェクト構造は、すぐに参照できるようにここに示されています。

WSDL2Apache CXF事前定義フォルダー

これで、 wsdl2java 生成クラスを使用してサーバーを作成する準備ができました。 wsdl2javaが作成したクラスを以下の図に示します-

WSDL2Apache CXF生成クラス

生成されたサービスインターフェイス

生成されたクラスのリストで、そのうちの1つがApache CXFインターフェースであることに注意してください。これは HelloWorldPortType.java です。 コードエディターでこのファイルを調べます。 ファイルの内容は、すぐに参照できるようにここに表示されます-

//HelloWorldPortType.java
package com.finddevguides.helloworld;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
/**
* This class was generated by Apache CXF 3.3.0
* 2019-02-11T12:05:55.220+05:30
* Generated source version: 3.3.0
*
*/

@WebService(targetNamespace = "http://helloworld.finddevguides.com/",
   name = "HelloWorldPortType")
@XmlSeeAlso({ObjectFactory.class})
public interface HelloWorldPortType {
   @WebMethod
   @RequestWrapper(localName = "greetings", targetNamespace =
      "http://helloworld.finddevguides.com/", className =
      "com.finddevguides.helloworld.Greetings")
      @ResponseWrapper(localName = "greetingsResponse", targetNamespace =
         "http://helloworld.finddevguides.com/", className =
         "com.finddevguides.helloworld.GreetingsResponse")
   @WebResult(name = "return", targetNamespace =
      "http://helloworld.finddevguides.com/")
   public java.lang.String greetings(
      @WebParam(name = "arg0", targetNamespace =
      "http://helloworld.finddevguides.com/")
      java.lang.String arg0
   );
}

インターフェイスには greetings というメソッドが含まれていることに注意してください。 これは、wsdlのメッセージタイプでした。 wsdl2java ツールは、生成されたインターフェースにこのメソッドを追加しました。 これで、wsdlに書き込むメッセージが何であれ、対応するメソッドがインターフェースで生成されることを理解できます。

ここで、タスクは、wsdlで定義したさまざまなメッセージに対応するこれらすべてのメソッドを実装することです。 Apache CXF-Firstの以前の例では、Webサービス用のApache CXFインターフェースから始めたことに注意してください。 この場合、Apache CXFインターフェースはwsdlから作成されます。

サービスインターフェイスの実装

サービスインターフェイスの実装は簡単です。 完全な実装は、以下のリストに示されています-

//HelloWorldImpl.java
package com.finddevguides.helloworld;
public class HelloWorldImpl implements HelloWorldPortType {
   @Override
   public String greetings(String name) {
      return ("hi " + name);
   }
}

このコードは、 greetings と呼ばれる唯一のインターフェイスメソッドを実装します。 このメソッドは string タイプのパラメーターを1つ受け取り、それに「hi」メッセージを付加して、結果のストリングを呼び出し元に返します。

次に、サーバーアプリケーションを作成します。

開発サーバー

サーバーアプリケーションの開発は簡単です。 ここでは、CXFが提供する Endpoint クラスを使用してサービスを公開します。 これは、次の2行のコードで行われます-

HelloWorldPortType implementor = new HelloWorldImpl();
   Endpoint.publish("http://localhost:9090/HelloServerPort",
      implementor,
      new LoggingFeature());

まず、サービス実装クラスのオブジェクト- HelloWorldImpl を作成します。 次に、この参照を publish メソッドの2番目のパラメーターとして渡します。 最初のパラメーターはサービスが公開されるアドレスです-クライアントはこのURLを使用してサービスにアクセスします。 サーバーアプリケーションのソース全体がここに与えられています-

//Server.java
package com.finddevguides.helloworld;
import javax.xml.ws.Endpoint;
import org.apache.cxf.ext.logging.LoggingFeature;
public class Server {
   public static void main(String[] args) throws Exception {
      HelloWorldPortType implementor = new HelloWorldImpl();
      Endpoint.publish("http://localhost:9090/HelloServerPort",
         implementor,
         new LoggingFeature());
      System.out.println("Server ready...");
      Thread.sleep(5 *60* 1000);
      System.out.println("Server exiting");
      System.exit(0);
   }
}

このサーバークラスをビルドするには、 pom.xml にビルドプロファイルを追加する必要があります。 これは以下に示されています-

<profile>
   <id>server</id>
   <build>
      <defaultGoal>test</defaultGoal>
      <plugins>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.6.0</version>
            <executions>
               <execution>
                  <phase>test</phase>
                  <goals>
                     <goal>java</goal>
                  </goals>
                  <configuration>
                     <mainClass>
                        com.finddevguides.helloworld.Server
                     </mainClass>
                  </configuration>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</profile>
*Server* クラスの完全修飾名が構成で指定されていることに注意してください。 また、依存関係タグは、埋め込みJetty Webサーバーを使用してサーバーアプリケーションを展開することを指定します。

サーバーの展開

最後に、サーバーアプリケーションをデプロイするには、pom.xmlをもう1つ変更して、アプリケーションをWebアプリケーションとして設定する必要があります。 あなたが pom.xml に追加する必要があるコードは以下のとおりです-

<defaultGoal>install</defaultGoal>
<pluginManagement>
   <plugins>
      <plugin>
         <artifactId>maven-war-plugin</artifactId>
         <version>3.2.2</version>
         <configuration>
            <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
            <webResources>
               <resource>
                  <directory>src/main/resources</directory>
                  <targetPath>WEB-INF</targetPath>
                  <includes>
                     <include>*.wsdl</include>
                  </includes>
               </resource>
            </webResources>
         </configuration>
      </plugin>
   </plugins>
</pluginManagement>

アプリケーションをデプロイする前に、プロジェクトにさらに2つのファイルを追加する必要があります。 これらは、以下のスクリーンショットに示されています-

WSDLアプリケーションのデプロイ前

これらのファイルは、 CXFServlet のマッピングを定義するCXF標準ファイルです。 web.xml ファイル内のコードは、クイックリファレンスのためにここに示されています-

//cxf-servlet.xml
<web-app xmlns = "http://java.sun.com/xml/ns/javaee"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" version="2.5"
   xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <display-name>cxf</display-name>
   <servlet>
      <description>Apache CXF Endpoint</description>
      <display-name>cxf</display-name>
      <servlet-name>cxf</servlet-name>
      <servlet-class>
         org.apache.cxf.transport.servlet.CXFServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>cxf</servlet-name>
      <url-pattern>/services/*</url-pattern>
   </servlet-mapping>
   <session-config>
      <session-timeout>60</session-timeout>
   </session-config>
</web-app>
*cxf-servlet.xml* で、サービスのエンドポイントのプロパティを宣言します。 これは以下のコードスニペットに示されています-
<beans ...>
   <jaxws:endpoint xmlns:helloworld = "http://finddevguides.com/"
      id="helloHTTP"
      address = "http://localhost:9090/HelloServerPort"
      serviceName = "helloworld:HelloServiceService"
      endpointName = "helloworld:HelloServicePort">
   </jaxws:endpoint>
</beans>

ここで、サービスエンドポイントのID、サービスを利用できるアドレス、サービス名、エンドポイント名を定義します。 これで、サービスがCXFサーブレットによってどのようにルーティングおよび処理されるかを理解できました。

最終的なpom.xml

*pom.xml* には、さらにいくつかの依存関係が含まれています。 すべての依存関係を記述するのではなく、pom.xmlの最終バージョンを以下に含めました-
<?xml version="1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.finddevguides</groupId>
   <artifactId>cxf-wsdl</artifactId>
   <version>1.0</version>
   <packaging>jar</packaging>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
   </properties>
   <build>
      <defaultGoal>install</defaultGoal>
      <pluginManagement>
         <plugins>
            <plugin>
               <artifactId>maven-war-plugin</artifactId>
               <version>3.2.2</version>
               <configuration>
                  <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
                  <webResources>
                     <resource>
                        <directory>src/main/resources</directory>
                        <targetPath>WEB-INF</targetPath>
                        <includes>
                           <include>*.wsdl</include>
                        </includes>
                     </resource>
                  </webResources>
               </configuration>
            </plugin>
         </plugins>
      </pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-codegen-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
               <execution>
                  <id>generate-sources</id>
                  <phase>generate-sources</phase>
                  <configuration>
                     <wsdlOptions>
                        <wsdlOption>
                           <wsdl>src/main/resources/Hello.wsdl</wsdl>
                           <faultSerialVersionUID>1</faultSerialVersionUID>
                        </wsdlOption>
                     </wsdlOptions>
                  </configuration>
                  <goals>
                     <goal>wsdl2java</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <profiles>
      <profile>
         <id>server</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <version>1.6.0</version>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.finddevguides.helloworld.Server
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
         <dependencies>
            <dependency>
               <groupId>org.apache.cxf</groupId>
               <artifactId>cxf-rt-transports-http-jetty</artifactId>
               <version>3.3.0</version>
            </dependency>
         </dependencies>
      </profile>
      <profile>
         <id>client</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.finddevguides.helloworld.Client
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-frontend-jaxws</artifactId>
         <version>3.3.0</version>
      </dependency>

      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http</artifactId>
         <version>3.3.0</version>
      </dependency>

      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-management</artifactId>
         <version>3.3.0</version>
      </dependency>

      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-metrics</artifactId>
         <version>3.3.0</version>
      </dependency>

      <dependency>
         <groupId>org.apache.cxf.xjc-utils</groupId>
         <artifactId>cxf-xjc-runtime</artifactId>
         <version>3.3.0</version>
      </dependency>

      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-logging</artifactId>
         <version>3.3.0</version>
      </dependency>

     <dependency>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>exec-maven-plugin</artifactId>
         <version>1.6.0</version>
      </dependency>

      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.8.0-beta2</version>
      </dependency>

      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</project>

クライアントを構築するためのプロファイルも含まれていることに注意してください。これについては、後のセクションで間もなく学習します。

HelloWorldサービスの実行

これで、Webアプリを実行する準備が整いました。 コマンドウィンドウで、次のコマンドを使用してビルドスクリプトを実行します。

mvn clean install

これにより、wsdlから適切なApache CXFクラスが生成され、Apache CXFクラスがコンパイルされ、組み込みJettyサーバーにサーバーがデプロイされ、アプリケーションが実行されます。

コンソールに次のメッセージが表示されます-

INFO: Setting the server's publish address to be
http://localhost:9090/HelloServerPort
Server ready...

前と同様に、ブラウザでサーバーURLを開いてサーバーをテストできます。

サーバーのURLを開く

操作を指定しなかったため、アプリケーションからエラーメッセージのみがブラウザに返されます。 ここで、*?wsdl *をURLに追加してみてください。次の出力が表示されます-

WSDL出力

したがって、サーバーアプリケーションは期待どおりに実行されています。 前述の Postman などのSOAPクライアントを使用して、サービスをさらにテストできます。

このチュートリアルの次の部分は、サービスを使用するクライアントを作成することです。

クライアントの開発

CXFアプリケーションでクライアントを作成することは、サーバーを作成することと同じくらい重要です。 基本的に3行のみで構成されるクライアントの完全なコードを次に示します。残りの行は、サービス情報をユーザーに出力するだけです。

//Client.java
package com.finddevguides.helloworld;
public class Client {
   public static void main(String[] args) throws Exception {
     //Create the service client with its default wsdlurl
      HelloWorldService helloServiceService = new HelloWorldService();
      System.out.println("service: " +
         helloServiceService.getServiceName());
      System.out.println("wsdl location: " +
         helloServiceService.getWSDLDocumentLocation());
      HelloWorldPortType helloService =
         helloServiceService.getHelloWorldPort();
      System.out.println(helloService.greetings
      (System.getProperty("user.name")));
   }
}

ここでは、サービス HelloWorldService のインスタンスを作成し、 getHelloWorldPort メソッドを呼び出してポートを取得してから、 greetings メッセージを渡します。 クライアントを実行すると、次の出力が表示されます-

service: {http://helloworld.finddevguides.com/}HelloWorldService
wsdl location: file:/Users/drsarang/Desktop/tutorialpoint/cxf-
wsdl/src/main/resources/Hello.wsdl
hi drsarang

これまで、Apache CXF-FirstおよびWSDL-FirstアーキテクチャーでCXFを使用する方法を学びました。 Apache CXF-Firstアプローチでは、CXFライブラリの ServerFactoryBean クラスでPOJOを使用してサーバーを作成しました。 クライアントを作成するには、CXFライブラリの ClientProxyFactoryBean クラスを使用しました。 WSDL-Firstアプローチでは、 Endpoint クラスを使用して、目的のURLおよび指定された実装者でサービスを公開しました。 これらの手法を拡張して、さまざまなプロトコルとトランスポートを統合できるようになりました。