Apache CXF с WSDL в первую очередь

Приложение CXF-POJO, которое вы разработали, обеспечивает очень тесную связь между клиентом и сервером. Предоставление прямого доступа к сервисному интерфейсу также может представлять серьезную угрозу безопасности. Таким образом, разделение между клиентом и сервером обычно желательно, что достигается с помощью WSDL (языка описания веб-служб).

Мы пишем интерфейс веб-службы в документе WSDL, основанном на XML. Мы будем использовать инструмент для сопоставления этого WSDL с интерфейсами Apache CXF, которые затем реализуются и используются нашими клиентскими и серверными приложениями. Для обеспечения развязки предпочтительным способом является использование WSDL. Для этого вам необходимо сначала выучить новый язык - WSDL. Написание WSDL требует осторожного подхода, и было бы лучше, если бы вы получили некоторое представление об этом, прежде чем начинать над ним работать.

В этом уроке мы начнем с определения интерфейса веб-службы в документе WSDL. Мы узнаем, как использовать CXF для создания как серверных, так и клиентских приложений, начиная с WSDL. Мы сохраним простоту приложения, чтобы сосредоточиться на использовании CXF. После создания серверного приложения мы опубликуем его по желаемому URL-адресу с помощью встроенного класса CXF.

Во-первых, давайте опишем WSDL, который мы собираемся использовать.

WSDL для HelloWorld

Веб-сервис, который мы собираемся реализовать, будет иметь один единственный веб-метод, называемый greetings который принимает 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.tutorialspoint.com/"
   xmlns:wsdl = "http://schemas.xmlsoap.org/wsdl/"
   xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
   name = "HelloWorld"
   targetNamespace = "http://helloworld.tutorialspoint.com/">
   <wsdl:types>
      <xsd:schema attributeFormDefault = "unqualified"
         elementFormDefault = "qualified"
         targetNamespace = "http://helloworld.tutorialspoint.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, вы можете вручную запрограммировать весь документ или использовать один из редакторов для создания своего собственного.

В приведенном выше wsdl мы определили одно сообщение с именем greetings. Сообщение доставляется в службу, которая называетсяHelloWorldService что работает на http://localhost:9090/HelloServerPort.

На этом мы перейдем к разработке сервера. Перед разработкой сервера нам необходимо сгенерировать интерфейс 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 в заранее определенной папке. Полная структура проекта представлена ​​здесь для вашего удобства.

Теперь вы готовы создать сервер, используя wsdl2javaсгенерированные классы. Классы, созданные wsdl2java, показаны на рисунке ниже -

Сгенерированный сервисный интерфейс

В списке сгенерированных классов вы, должно быть, заметили, что один из них является интерфейсом Apache CXF - это HelloWorldPortType.java. Изучите этот файл в своем редакторе кода. Содержимое файла показано здесь для вашего удобства -

//HelloWorldPortType.java
package com.tutorialspoint.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.tutorialspoint.com/",
   name = "HelloWorldPortType")
@XmlSeeAlso({ObjectFactory.class})
public interface HelloWorldPortType {
   @WebMethod
   @RequestWrapper(localName = "greetings", targetNamespace =
      "http://helloworld.tutorialspoint.com/", className =
      "com.tutorialspoint.helloworld.Greetings")
      @ResponseWrapper(localName = "greetingsResponse", targetNamespace =
         "http://helloworld.tutorialspoint.com/", className =
         "com.tutorialspoint.helloworld.GreetingsResponse")
   @WebResult(name = "return", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
   public java.lang.String greetings(
      @WebParam(name = "arg0", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
      java.lang.String arg0
   );
}

Обратите внимание, что интерфейс содержит метод, называемый greetings. Это был тип сообщения в нашем wsdl. Вwsdl2javaинструмент добавил этот метод в сгенерированный интерфейс. Теперь вы можете понять, что какие бы сообщения вы ни писали в wsdl, соответствующий метод будет сгенерирован в интерфейсе.

Теперь ваша задача - реализовать все эти методы, соответствующие различным сообщениям, которые вы определили в своем wsdl. Обратите внимание, что в предыдущем примере Apache CXF-First мы начали с интерфейса Apache CXF для нашей веб-службы. В этом случае интерфейс Apache CXF создается из wsdl.

Реализация сервисного интерфейса

Реализация служебного интерфейса тривиальна. Полная реализация показана в листинге ниже -

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

В коде реализован единственный интерфейсный метод, называемый greetings. Метод принимает один параметр изstring type, добавляет к нему сообщение «привет» и возвращает полученную строку вызывающему.

Далее мы напишем серверное приложение.

Сервер разработки

Разработка серверного приложения снова тривиальна. Здесь мы будем использовать поставляемый CXFEndpointкласс для публикации нашего сервиса. Это делается в следующих двух строках кода -

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

Сначала мы создаем объект нашего класса реализатора службы - HelloWorldImpl. Затем мы передаем эту ссылку в качестве второго параметра вpublishметод. Первый параметр - это адрес, по которому публикуется служба - клиенты будут использовать этот URL-адрес для доступа к службе. Полный исходный код серверного приложения приведен здесь -

//Server.java
package com.tutorialspoint.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.tutorialspoint.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класс указывается в конфигурации. Кроме того, тег зависимости указывает, что мы будем использовать встроенный веб-сервер причала для развертывания нашего серверного приложения.

Развертывание сервера

Наконец, чтобы развернуть серверное приложение, вам нужно будет внести еще одну модификацию в pom.xml, чтобы настроить ваше приложение как веб-приложение. Код, который вам нужно добавить в свой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>

Перед развертыванием приложения вам необходимо добавить в проект еще два файла. Они показаны на скриншоте ниже -

Эти файлы являются стандартными файлами CXF, которые определяют сопоставление для CXFServlet. Код в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://tutorialspoint.com/"
      id="helloHTTP"
      address = "http://localhost:9090/HelloServerPort"
      serviceName = "helloworld:HelloServiceService"
      endpointName = "helloworld:HelloServicePort">
   </jaxws:endpoint>
</beans>

Здесь мы определяем идентификатор для нашей конечной точки службы, адрес, по которому служба будет доступна, имя службы и имя конечной точки. Теперь вы понимаете, как ваш сервис маршрутизируется и обрабатывается сервлетом 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.tutorialspoint</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.tutorialspoint.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.tutorialspoint.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

Теперь вы готовы запустить веб-приложение. В командном окне запустите сценарий сборки, используя следующую команду.

mvn clean install

Это сгенерирует соответствующие классы Apache CXF из вашего wsdl, скомпилирует ваши классы Apache CXF, развернет сервер на встроенном сервере причала и запустит ваше приложение.

Вы увидите следующее сообщение на консоли -

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

Как и раньше, вы можете протестировать сервер, открыв URL-адрес сервера в браузере.

Поскольку мы не указали никаких операций, наше приложение возвращает браузеру только сообщение об ошибке. Теперь попробуйте добавить?wsdl на свой URL-адрес, и вы увидите следующий результат -

Итак, наше серверное приложение работает, как ожидалось. Вы можете использовать клиент SOAP, напримерPostman описанный ранее для дальнейшего тестирования вашей службы.

Следующая часть этого руководства - написание клиента, использующего наш сервис.

Развивающийся клиент

Написание клиента в приложении CXF так же важно, как и создание сервера. Вот полный код для клиента, который по существу состоит всего из трех строк, остальные строки просто выводят служебную информацию для пользователя.

//Client.java
package com.tutorialspoint.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.tutorialspoint.com/}HelloWorldService
wsdl location: file:/Users/drsarang/Desktop/tutorialpoint/cxf-
wsdl/src/main/resources/Hello.wsdl
hi drsarang

Итак, вы узнали, как использовать CXF с архитектурами Apache CXF-First и WSDL-First. В подходе Apache CXF-First вы использовали POJO сServerFactoryBeanкласс из библиотек CXF для создания сервера. Для создания клиента вы использовалиClientProxyFactoryBeanкласс из библиотеки CXF. В подходе WSDL-First вы использовалиEndpointкласс для публикации службы по желаемому URL-адресу и указанному разработчику. Теперь вы можете расширить эти методы для интеграции различных протоколов и транспортов.