Учебники

Apache CXF — Краткое руководство

Apache CXF — Введение

В сегодняшней среде вы можете создать приложение веб-службы, используя несколько опций. Вы можете использовать один или несколько из нескольких стандартных и общепринятых протоколов для связи. Например, SOAP , XML / HTTP, RESTful HTTP и CORBA (Архитектура Common Object Request Broker, которая была очень популярна в древние времена, но не так часто используется сейчас.

У вас также есть выбор различных транспортов, таких как HTTP, JMS , JBI и выбор интерфейсных API, таких как JAX-RS и JAX-WS . Имея так много опций для разработки веб-сервисов, существует потребность в сервисах с открытым исходным кодом, чтобы склеить все вышеупомянутые опции, и это то, что делает Apache CXF .

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

В этом руководстве подробно рассматривается разработка следующих проектов:

  • CXF с простыми старыми объектами Apache CXF (POJO)

  • CXF с JAX-WS

  • CXF с WSDL

  • CXF с JAX-RS

  • CXF с JMS

CXF с простыми старыми объектами Apache CXF (POJO)

CXF с JAX-WS

CXF с WSDL

CXF с JAX-RS

CXF с JMS

Для простоты мы использовали maven с интерфейсом командной строки. Вы можете использовать предпочитаемую IDE для создания проекта maven.

В следующей главе давайте начнем с первой.

Apache CXF с POJO

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

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

Сначала мы создадим веб-сервис. Каждый сервис имеет интерфейс, доступный клиенту. Мы можем написать этот интерфейс как простой интерфейс Apache CXF или как документ WSDL. В этом подходе Apache CXF-First мы представим наш сервис через интерфейс Apache CXF.

Разработка веб-сервиса

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

Интерфейс веб-службы

Чтобы представить интерфейс нашего веб-сервиса, мы создадим интерфейс Apache CXF следующим образом:

//HelloWorld.java
package com.tutorialspoint.cxf.pojo;
public interface HelloWorld {
   String greetings(String text);
}

Интерфейс имеет только один метод с именем приветствия . Сервер будет реализовывать этот интерфейс. В нашем простом приложении этот интерфейс напрямую предоставляется клиенту. Как правило, в приложении веб-службы вы используете WSDL для описания интерфейса веб-службы. В этом простом приложении мы предоставим этот прямой интерфейс клиентскому разработчику. Затем клиент вызовет приветственное сообщение на объекте сервера. Итак, сначала давайте создадим веб-сервис.

Реализация веб-сервиса

Интерфейс HelloWorld реализован в классе HelloWorldImpl Apache CXF, как показано ниже —

//HelloWorldImpl.java
package com.tutorialspoint.cxf.pojo;
public class HelloWorldImpl implements HelloWorld {
   @Override
   public String greetings(String text) {
      return "Hi " + text;
   }
}

Метод greetings получает параметр строкового типа, добавляет его к приветственному сообщению и возвращает результирующую строку вызывающей стороне.

Далее мы пишем серверное приложение для размещения сервиса HelloWorld .

Создание сервера

Серверное приложение состоит из двух частей —

  • Первая часть создает фабрику для нашего веб-сервиса, и

  • Вторая часть описывает основной метод для его создания.

Первая часть создает фабрику для нашего веб-сервиса, и

Вторая часть описывает основной метод для его создания.

Сервер использует класс ServerFactoryBean, предоставляемый библиотеками CXF, для предоставления нашего интерфейса HelloWorld удаленным клиентам. Таким образом, мы сначала создаем экземпляр класса ServerFactoryBean, а затем устанавливаем его различные свойства —

ServerFactoryBean factory = new ServerFactoryBean();

Мы устанавливаем класс сервиса, который будет вызываться путем вызова метода setServiceClass объекта фабрики

factory.setServiceClass(HelloWorld.class);

Мы устанавливаем URL для вызова нашего сервиса, вызывая фабричный метод setAddress . Обратите внимание, что сервис будет опубликован по этому URL.

factory.setAddress("http://localhost:5000/Hello");

В этом случае служба развернута на встроенном сервере и будет прослушивать порт 5000. Вы можете выбрать любой номер порта по вашему выбору.

Перед созданием фабрики необходимо рассказать фабрике о классе реализации нашего сервиса. Это делается путем вызова метода setServiceBean для объекта фабрики, как показано здесь —

factory.setServiceBean(new HelloWorldImpl());

Сервисный компонент устанавливается на экземпляр нашего класса реализации сервиса. Наконец, мы создаем фабрику, вызывая ее метод создания

factory.create();

Теперь, когда мы разработали фабрику для запуска нашего веб-сервиса, мы напишем метод main для его создания и продолжения работы в течение некоторого времени.

Теперь напишите основной метод для создания экземпляра класса HelloServer следующим образом:

public static void main(String[] args) throws Exception {
   new HelloServer();
   System.out.println("Listening on port 5000 ...");
}

После создания класс HelloServer будет работать бесконечно долго. Для производственных развертываний ваш сервер будет работать вечно. В текущей ситуации мы завершаем работу сервера через заданное время следующим образом:

Thread.sleep(5 * 60 * 1000);
System.out.println("Server exiting ...");
System.exit(0);

Весь код для класса HelloServer приведен ниже —

//HelloServer.java
//HelloServer.java
package com.tutorialspoint.cxf.pojo;
import org.apache.cxf.frontend.ServerFactoryBean;
public class HelloServer {
   protected HelloServer() throws Exception {
      ServerFactoryBean factory = new ServerFactoryBean();
      factory.setServiceClass(HelloWorld.class);
      factory.setAddress("http://localhost:5000/Hello");
      factory.setServiceBean(new HelloWorldImpl());
      factory.create();
   }
   public static void main(String[] args) throws Exception {
      new HelloServer();
      System.out.println("Listening on port 5000 ...");
      Thread.sleep(5 * 60 * 1000);
      System.out.println("Server exiting ...");
      System.exit(0);
   }
}

Созданное нами серверное приложение использует класс ServerFactoryBean из библиотек CXF. Теперь мы должны включить эти библиотеки в наш проект, чтобы успешно скомпилировать класс HelloServer . Мы будем использовать Maven для настройки зависимостей проекта.

Настройка проекта Maven

Чтобы создать проект Maven, введите следующую команду в окне командной строки. Обратите внимание, что мы проверили это на компьютере Mac. Для установок Windows и Linux инструкции могут отличаться в нескольких местах.

mvn archetype:generate

Когда спросят о свойствах, введите следующие значения —

Define value for property 'groupId': : com.tutorialspoint
Define value for property 'artifactId': : cxf-pojo
Define value for property 'version': 1.0-SNAPSHOT: : 1.0
Define value for property 'package': com.tutorialspoint: : com.tutorialspoint.cxf.pojo

После завершения команды maven вы найдете соответствующую структуру папок, созданную в вашей текущей папке вместе с файлом pom.xml.

Сгенерированная структура каталогов показана здесь —

Структура каталогов

Вы добавите зависимости CXF в файл pom.xml, а также скопируете созданные выше файлы Apache CXF в соответствующую папку созданной maven структуры. Для вашей справки мы дали ниже файл 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-pojo</artifactId>
   <version>1.0</version>
   <packaging>jar</packaging>
   
   <profiles>
      <profile>
         <id>server</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.cxf.pojo.HelloServer
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </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.cxf.pojo.HelloClient
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>

   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-logging</artifactId>
         <version>3.3.0</version>
         <type>jar</type>
      </dependency>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-frontend-simple</artifactId>
         <version>3.3.0</version>
         <type>jar</type>
      </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-frontend-jaxws</artifactId>
         <version>3.3.0</version>
      </dependency>
      <!-- Jetty is needed if you're using the CXFServlet -->
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
   <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>
</project>

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

Структура папки проекта

Структура папок проекта на моем компьютере после размещения файлов сервера и клиента Apache CXF показана ниже для краткого ознакомления.

Структура папки проекта

Запущенный сервер

Чтобы построить проект, используйте следующую команду в окне командной строки:

mvn clean install

Вы можете запустить сервер, используя следующую команду —

mvn -Pserver

Это запустит сервер, и вы увидите следующее приглашение на консоли —

INFO: Creating Service {http://pojo.cxf.tutorialspoint.com/}HelloWorld from class com.tutorialspoint.cxf.pojo.HelloWorld
INFO: Setting the server's publish address to be http://localhost:5000/Hello
Listening on port 5000 ...

Теперь в окне вашего браузера укажите URL нашего опубликованного сервиса. Вы увидите следующий вывод —

Дерево выходного документа

Это подтверждает, что наш сервис работает на указанном порту на локальном хосте. Поскольку мы не указали приветственное сообщение в нашем вызове, сообщение об ошибке SOAP возвращается в браузер.

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

Вывод как показано здесь —

Запуск выходного сервера

Обратите внимание, что SOAP-запрос был закодирован вручную. После публикации запроса сервер отправил ответное сообщение SOAP , которое видно в нижней части снимка экрана.

Из этого вы можете понять, что CXF поддерживает использование протоколов SOAP как для запросов, так и для ответов, одновременно предоставляя вам единое представление о различных веб-технологиях, существующих в современном мире. Это значительно упрощает разработку веб-приложений.

Наша следующая задача — создать клиент, который будет использовать созданный вами веб-сервис.

Создание клиента

В серверном приложении HelloWorld есть интерфейс, который предоставляет наш веб-сервис. Сам веб-сервис просто предоставляет клиенту простое приветственное сообщение. Обычно интерфейс веб-службы открыт для внешнего мира с использованием WSDL (языка описания веб-служб). В этом тривиальном приложении мы представим клиенту наш веб-сервис, предоставив непосредственно интерфейс сервиса, и это HelloWorld.class .

Для этой цели CXF предоставляет класс фабрики ClientProxyFactoryBean, который позволяет нам подключаться к желаемому интерфейсу к созданному экземпляру фабрики.

Сначала мы создаем экземпляр фабричного компонента следующим образом:

ClientProxyFactoryBean factory = new ClientProxyFactoryBean();

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

factory.setAddress("http://localhost:5000/Hello");

Затем мы вызываем метод create для экземпляра фабрики, чтобы присоединить к нему наш интерфейс службы HelloWorld.class .

HelloWorld helloServer = factory.create(HelloWorld.class);

Наконец, мы вызываем метод приветствия для вызова удаленного веб-сервиса.

System.out.println(helloServer.greetings(System.getProperty("user.name")));

Это напечатало бы приветственное сообщение на вашей консоли.

Весь исходный код клиентского приложения показан ниже —

//HelloClient.java
package com.tutorialspoint.cxf.pojo;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
public class HelloClient {
   public static void main(String[] args) throws Exception {
      ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
      factory.setAddress("http://localhost:5000/Hello");
      HelloWorld helloServer = factory.create(HelloWorld.class);
      System.out.println(helloServer.greetings(System.getProperty("user.name")));
   }
}

Бегущий клиент

Убедитесь, что сервер все еще работает на вашем компьютере. В случае, если истекло время ожидания, перезапустите сервер с помощью следующей команды —

mvn -Pserver

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

Listening on port 5000 ...

Теперь, до истечения времени ожидания сервера, которое мы установили на 5 минут, откройте другое окно командной строки и запустите клиент с помощью следующей команды —

mvn -Pclient

В командной строке вы увидите сообщение, подобное следующему:

Hi tutorialspoint

Обратите внимание, что tutorialspoint — это наше имя пользователя. Вы получите приветствие со своим именем.

В следующей главе мы узнаем, как использовать CXF в проекте JAX-WS (API Apache CXF для веб-служб XML).

Apache CXF с JAX-WS

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

Объявление сервисного интерфейса

Как и в предыдущем случае, мы создадим тривиальный сервис, который имеет только один интерфейсный метод, называемый приветствиями. Код для интерфейса службы показан ниже —

//HelloWorld.java
package com.tutorialspoint.cxf.jaxws.helloworld;
import javax.jws.WebService;

@WebService
public interface HelloWorld {
   String greetings(String text);
}

Мы аннотируем интерфейс тегом @WebService . Далее мы реализуем этот интерфейс.

Реализация веб-интерфейса

Реализация веб-интерфейса показана здесь —

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

Метод приветствия помечен тегом @Override . Метод возвращает сообщение «привет» вызывающей стороне.

Далее мы напишем код для разработки сервера.

Развивающийся сервер

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

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

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

//Server.java
package com.tutorialspoint.cxf.jaxws.helloworld;
import javax.xml.ws.Endpoint;
import org.apache.cxf.ext.logging.LoggingFeature;
public class Server {
   public static void main(String[] args) throws Exception {
      HelloWorld 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, чтобы настроить приложение как веб-приложение. Код, который вам нужно добавить в ваш pom.xml , приведен ниже —

<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.cxf.jaxws.helloworld.Server
                        </mainClass>
                     </configuration>
                  </execution>
               </executions>
            </plugin>
         </plugins>
      </build>
   </profile>
</profiles>

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

Перед развертыванием приложения JAXWS

Эти файлы являются стандартными файлами CXF, которые определяют отображение для CXFServlet . Код в файле web.xml показан здесь для вашего быстрого ознакомления —

//Web.xml
<?xml version = "1.0" encoding = "UTF-8"??>
<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-jaxws</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>
   <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.cxf.jaxws.helloworld.Server
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </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.cxf.jaxws.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-features-logging</artifactId>
         <version>3.3.0</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
mvn -Pserver

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

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

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

URL открытия сервера

Поскольку мы не указали никакой операции, наше приложение возвращает браузеру только сообщение об ошибке.

Теперь попробуйте добавить ? Wsdl в ваш URL, и вы увидите следующий результат:

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

В следующем разделе мы узнаем, как написать клиент, который использует наш сервис.

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

Написание клиента в приложении CXF столь же тривиально, как написание сервера. Вот полный код для клиента —

//Client.java
package com.tutorialspoint.cxf.jaxws.helloworld;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
public final class Client {
   private static final QName SERVICE_NAME
   = new QName("http://helloworld.jaxws.cxf.tutorialspoint.com/",
   "HelloWorld");
   private static final QName PORT_NAME
   = new QName("http://helloworld.jaxws.cxf.tutorialspoint.com/",
   "HelloWorldPort");
   private Client() {
   }
   public static void main(String[] args) throws Exception {
      Service service = Service.create(SERVICE_NAME);
      System.out.println("service created");
      String endpointAddress = "http://localhost:9090/HelloServerPort";
      service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING,
      endpointAddress);
      HelloWorld hw = service.getPort(HelloWorld.class);
      System.out.println(hw.greetings("World"));
   }
}

Здесь мы используем предоставляемый CXF класс Service для привязки к известному сервису. Мы вызываем метод create для класса Service, чтобы получить экземпляр сервиса. Мы устанавливаем известный порт, вызывая метод addPort в экземпляре службы .

Теперь мы готовы использовать службу, что мы и делаем, сначала получая интерфейс службы, вызывая метод getPort в экземпляре службы . Наконец, мы вызываем наш метод приветствия, чтобы напечатать сообщение приветствия на консоли.

Теперь, когда вы изучили основы CXF с использованием подхода Apache CXF-First, теперь вы узнаете, как использовать CXF с подходом WSDL-First в нашей следующей главе.

Apache CXF с WSDL первым

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

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

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

Сначала давайте опишем WSDL, который мы собираемся использовать.

WSDL для HelloWorld

Веб-сервис, который мы собираемся реализовать, будет иметь один единственный веб-метод, называемый greetings, который принимает строковый параметр, содержащий имя пользователя, и возвращает строковое сообщение вызывающей стороне после добавления сообщения приветствия к имени пользователя. Полный 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 мы определили одно сообщение под названием приветствия . Сообщение доставляется в службу под названием 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 в предопределенной папке. Полная структура проекта показана здесь для вашего удобства.

Предопределенная папка WSDL2Apache CXF

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

WSDL2Apache CXF сгенерированные классы

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

В списке сгенерированных классов вы должны были заметить, что один из них — это интерфейс 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);
   }
}

Код реализует единственный интерфейсный метод, называемый приветствиями . Метод принимает один параметр строкового типа, добавляет к нему сообщение «hi» и возвращает результирующую строку вызывающей стороне.

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

Развивающийся сервер

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

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

Сначала мы создаем объект нашего класса реализации сервиса — HelloWorldImpl . Затем мы передаем эту ссылку в качестве второго параметра методу публикации . Первый параметр — это адрес, по которому публикуется сервис — клиенты будут использовать этот 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 указывается в конфигурации. Кроме того, тег зависимостей указывает, что мы будем использовать встроенный веб-сервер Jetty для развертывания нашего серверного приложения.

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

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

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

Перед развертыванием приложения WSDL

Эти файлы являются стандартными файлами 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, развернет сервер на встроенном сервере Jetty и запустит ваше приложение.

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

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

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

URL открытия сервера

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

Выход WSDL

Итак, наше серверное приложение работает, как и ожидалось. Вы можете использовать клиент 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 , а затем передаем ему приветственное сообщение. Запустите клиент, и вы увидите следующий вывод —

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 и указанному разработчику. Теперь вы можете расширить эти методы для интеграции различных протоколов и транспортов.

Apache CXF с JAX-RS

Прежде чем перейти к этой главе, мы предполагаем, что вы знаете, как написать веб-сервис RESTful на Java. Я покажу вам, как использовать CXF поверх этого JAX-RS (Java API для веб-служб RESTful). Мы создадим веб-сервис, который ведет список последних фильмов. Когда пользователь запрашивает фильм, он указывает идентификатор фильма в своем запросе, сервер найдет фильм и вернет его клиенту. В нашем тривиальном случае мы просто вернем название фильма клиенту, а не фактический двоичный файл MP4. Итак, давайте начнем создавать приложение JAX-RS.

Объявление элемента фильма

Мы объявим корневой элемент XML под названием Movie для хранения идентификатора и имени данного фильма. Элемент объявлен в файле с именем Movie.java. Содержание файла показано здесь —

//Movie.java
package com.tutorialspoint.cxf.jaxrs.movie;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Movie")
public class Movie {
   private long id;
   private String name;
   public long getId() {
      return id;
   }
   public void setId(long id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}

Обратите внимание на использование тега XmlRootElement для объявления элемента XML для тега Movie . Далее мы создадим сервис, который хранит список фильмов в своей базе данных.

Создание базы данных сервиса фильмов

Для хранения списка фильмов мы используем предоставляемую Java карту, которая хранит пары ключ-значение. Если список большой, вы будете использовать внешнее хранилище базы данных, которым также будет легче управлять. В нашем тривиальном случае мы будем хранить только пять фильмов в нашей базе данных. Код для класса MovieService приведен ниже —

//MovieService.java
package com.tutorialspoint.cxf.jaxrs.movie;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@Path("/movieservice/")
@Produces("text/xml")
public class MovieService {
   long currentId = 123;
   Map<Long, Movie> movies = new HashMap<>();
   public MovieService() {
      init();
   }
   @GET
   @Path("/movie/{id}/")
   public Movie getMovie(@PathParam("id") String id) {
      long idNumber = Long.parseLong(id);
      return movies.get(idNumber);
   }
   final void init() {
      Movie c1 = new Movie();
      c1.setName("Aquaman");
      c1.setId(1001);
      movies.put(c1.getId(), c1);
      
      Movie c2 = new Movie();
      c2.setName("Mission Imposssible");
      c2.setId(1002);
      movies.put(c2.getId(), c2);
      
      Movie c3 = new Movie();
      c3.setName("Black Panther");
      c3.setId(1003);
      movies.put(c3.getId(), c3);
      
      Movie c4 = new Movie();
      c4.setName("A Star is Born");
      c4.setId(1004);
      movies.put(c4.getId(), c4);
      
      Movie c5 = new Movie();
      c5.setName("The Meg");
      c5.setId(1005);
      movies.put(c5.getId(), c5);
   }
}

Обратите внимание, что мы используем следующие две аннотации, чтобы указать путь к URL для нашего сервиса фильмов и тип его возврата:

@Path("/movieservice/")
@Produces("text/xml")

Мы используем аннотации @GET и @Path, чтобы указать URL-адрес для запроса GET следующим образом:

@GET
@Path("/movie/{id}/")

Сама база данных фильма инициализируется в методе init, где мы добавляем пять элементов фильма в базу данных.

Наша следующая задача — написать серверное приложение.

Развивающийся сервер

Для создания сервера мы используем предоставленный CXF класс JAXRSServerFactoryBean .

JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();

Мы устанавливаем его классы ресурсов, вызывая метод setResourceClasses .

factory.setResourceClasses(Movie.class);
factory.setResourceClasses(MovieService.class);

Мы устанавливаем поставщика услуг, вызывая метод setResourceProvider .

factory.setResourceProvider(MovieService.class,
new SingletonResourceProvider(new MovieService()));

Мы устанавливаем желаемый адрес публикации , вызывая метод aetAddress

factory.setAddress("http://localhost:9000/");

Наконец, мы публикуем сервер, вызывая метод create для экземпляра фабрики .

factory.create();

Весь код для серверного приложения приведен ниже —

//Server.java
package com.tutorialspoint.cxf.jaxrs.movie;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
public class Server {
   public static void main(String[] args) throws Exception {
      JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
      factory.setResourceClasses(Movie.class);
      factory.setResourceClasses(MovieService.class);  
      factory.setResourceProvider(MovieService.class,
         new SingletonResourceProvider(new MovieService()));
      factory.setAddress("http://localhost:9000/");
      factory.create();
      
      System.out.println("Server ready...");
      Thread.sleep(5 * 60 * 1000);
      
      System.out.println("Server exiting ...");
      System.exit(0);
   }
}

Финал 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-jaxrs</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>
   <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.cxf.jaxrs.movie.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.cxf.jaxrs.movie.Client
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>
   <dependencies>
      <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-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-frontend-jaxrs</artifactId>
         <version>3.3.0</version>
         </dependency>
      <dependency>
         <groupId>jakarta.ws.rs</groupId>
         <artifactId>jakarta.ws.rs-api</artifactId>
         <version>2.1.5</version>
      </dependency>
      <dependency>
         <groupId>org.apache.httpcomponents</groupId>
         <artifactId>httpclient</artifactId>
         <version>4.5.7</version>
      </dependency>
   </dependencies>
</project>

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

Написание RS-клиента тривиально. Мы просто создаем объект URL и открываем его поток. Мы используем предоставленный CXF класс IOUtils для копирования содержимого входного потока в локальный поток.

URL url = new URL("http://localhost:9000/movieservice/movie/1002");
try (InputStream instream = url.openStream();
CachedOutputStream outstream = new CachedOutputStream()) {
   IOUtils.copy(instream, outstream);
}

Весь код для клиентского приложения приведен ниже —

//Client.java
package com.tutorialspoint.cxf.jaxrs.movie;
import java.io.InputStream;
import java.net.URL;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.io.CachedOutputStream;
public class Client {
   public static void main(String[] args) throws Exception {
      URL url = new URL("http://localhost:9000/movieservice/movie/1002");
      try (InputStream instream = url.openStream();
      CachedOutputStream outstream = new CachedOutputStream()) {
         IOUtils.copy(instream, outstream);
         String str = outstream.getOut().toString();
         System.out.println(str);
      }
   }
}

Тестирование приложения JAX-RS

Запустите сервер, используя следующую команду в окне командной строки:

mvn -Pserver

Теперь на консоли вы увидите следующее сообщение:

INFO: Setting the server's publish address to be http://localhost:9000

Теперь откройте браузер и введите следующий URL —

http://localhost:9000/movieservice/movie/1002

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

окно браузера

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

mvn -Pclient

Вы увидите следующий вывод —

<?xml version="1.0" encoding = "UTF-8" standalone="yes"?>
<Movie><id>1002</id><name>Mission Imposssible</name></Movie>

Примеры CXF предоставляют несколько примеров того, как использовать CXF с JAX-RS. Заинтересованным читателям предлагается изучить эти образцы.

Apache CXF с JMS

Как упоминалось ранее, вы можете использовать CXF с транспортом JMS. В этом случае клиент отправит сообщение JMS известному серверу обмена сообщениями. Наше серверное приложение постоянно прослушивает сервер сообщений на предмет входящих сообщений. Когда приходит сообщение, оно обрабатывает сообщение, выполняет запрос клиента и отправляет ответ как другое сообщение клиенту.

Как и ранее, мы сначала создадим пример серверного приложения, которое предоставляет особый веб-метод sayHi .

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

Интерфейс сервиса для нашего сервиса HelloWorld показан здесь —

//HelloWorld.java
package com.tutorialspoint.service;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService
public interface HelloWorld {
   @WebMethod
   String sayHi(@WebParam(name = "name") String name);
}

Реализация сервиса

Реализация интерфейса службы определяется следующим образом:

//HelloWorldImpl.java
package com.tutorialspoint.service.impl;

import javax.jws.WebService;
import com.tutorialspoint.service.HelloWorld;

@WebService
public class HelloWorldImpl implements HelloWorld {
   @Override
   public String sayHi(String name) {
      return "Hello " + name;
   }
}

Реализация просто возвращает приветственное сообщение пользователю. Как видите, интерфейс и его реализация аналогичны всем более ранним проектам в этом руководстве, которые вы изучали до сих пор.

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

Создание сервера

В серверном приложении сначала мы создаем конечную точку JMS следующим образом:

private static final String JMS_ENDPOINT_URI =
   "jms:queue:test.cxf.jmstransport.queue?timeToLive=1000"
      + "&jndiConnectionFactoryName=ConnectionFactory"
      + "&jndiInitialContextFactory"
      + "= org.apache.activemq.jndi.ActiveMQInitialContextFactory"
      + "&jndiURL = tcp://localhost:61616";

Обратите внимание, что мы настроили очередь на указанном порту, которая живет определенное количество времени. Теперь мы создаем службу обмена сообщениями, создав экземпляр класса org.apache.activemq.broker.BrokerService . Это класс сервера для сервера сообщений ActiveMQ .

BrokerService broker = new BrokerService();

Вы можете использовать любой другой сервер сообщений по вашему выбору, кроме ActiveMQ . Теперь мы подключаем этот сервер к желаемому URI.

broker.addConnector("tcp://localhost:61616");

Мы настраиваем каталог для хранения данных входящих сообщений —

broker.setDataDirectory("target/activemq-data");

Наконец, мы запускаем сервер, используя метод запуска —

broker.start();

Затем мы создаем экземпляр нашего сервисного компонента HelloWorld, используя класс bean-компонента фабрики серверов, который использовался в нашем предыдущем приложении POJO —

Object implementor = new HelloWorldImpl();
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
factory.setServiceClass(HelloWorld.class);

Затем мы устанавливаем конечную точку JMS на заводе, чтобы фабрика продолжала прослушивать входящие сообщения —

factory.setTransportId
(JMSSpecConstants.SOAP_JMS_SPECIFICATION_TRANSPORTID);
factory.setAddress(JMS_ENDPOINT_URI);

Наконец, мы устанавливаем класс реализатора на фабрике и запускаем его —

factory.setServiceBean(implementor);
factory.create();

В этот момент ваш сервер запущен и работает. Обратите внимание, что поскольку мы использовали класс bean-компонентов фабрики, как в приложении POJO, необходимость в CXFServlet и файле web.xml не требуется.

Полный код серверного приложения показан здесь —

//ServerJMS.java
package com.tutorialspoint.server;

import java.util.Collections;
import org.apache.cxf.ext.logging.LoggingFeature;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.transport.jms.spec.JMSSpecConstants;
import com.tutorialspoint.service.HelloWorld;
import com.tutorialspoint.service.impl.HelloWorldImpl;
import org.apache.activemq.broker.BrokerService;

public final class ServerJMS {

   private static final String JMS_ENDPOINT_URI = 
      "jms:queue:test.cxf.jmstransport.queue?timeToLive=1000"
         + "&jndiConnectionFactoryName=ConnectionFactory"
         + "&jndiInitialContextFactory"
         + "= org.apache.activemq.jndi.ActiveMQInitialContextFactory"
         + "&jndiURL = tcp://localhost:61616";

   public static void main(String[] args) throws Exception {

      BrokerService broker = new BrokerService();
      broker.addConnector("tcp://localhost:61616");
      broker.setDataDirectory("target/activemq-data");
      broker.start();

      Object implementor = new HelloWorldImpl();
      JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
      factory.setServiceClass(HelloWorld.class);
      factory.setTransportId
      (JMSSpecConstants.SOAP_JMS_SPECIFICATION_TRANSPORTID);
      factory.setAddress(JMS_ENDPOINT_URI);
      factory.setServiceBean(implementor);
      factory.setFeatures(Collections.singletonList(new LoggingFeature()));
      factory.create();

      System.out.println("Server ready...");
      Thread.sleep(5 * 60 * 1000);
      System.out.println("Server exiting");
      System.exit(0);
   }
}

Добавление зависимостей

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

   <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.server.ServerJMS
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </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.client.ClientJMS
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>

   <dependencies>
      <dependency>
         <groupId>org.apache.activemq</groupId>
         <artifactId>activemq-broker</artifactId>
         <version>5.15.8</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.activemq</groupId>
         <artifactId>activemq-kahadb-store</artifactId>
         <version>5.15.8</version>
      </dependency>
      
      <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-jms</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.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</project>

Запущенный сервер

Чтобы запустить сервер, как и в предыдущих случаях, введите в командной строке следующую команду —

mvn -Pserver

Это запустит сервер сообщений ActiveMQ, настроит очередь сообщений и создаст фабричный компонент, который продолжает прослушивать эту очередь.

Наша следующая задача — создать клиентское приложение.

Создание клиента

В клиентском приложении сначала мы устанавливаем конечную точку JMS так же, как та, которая используется в серверном приложении —

private static final String JMS_ENDPOINT_URI =
   "jms:queue:test.cxf.jmstransport.queue?timeToLive=1000"
      + "&jndiConnectionFactoryName=ConnectionFactory"
      + "&jndiInitialContextFactory"
      + " = org.apache.activemq.jndi.ActiveMQInitialContextFactory"
      + "&jndiURL = tcp://localhost:61616";

Мы создаем фабрику как в приложении POJO.

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

Мы устанавливаем URI конечной точки и класс реализатора следующим образом:

factory.setTransportId (JMSSpecConstants.SOAP_JMS_SPECIFICATION_TRANSPORTID);
factory.setAddress (JMS_ENDPOINT_URI);
HelloWorld client = factory.create(HelloWorld.class);

Наконец, мы вызываем метод сервиса и выводим его результирующий вывод —

String reply = client.sayHi("TutorialsPoint");
System.out.println(reply);

Полный код клиента приведен ниже —

// ClientJMS.java
package com.tutorialspoint.client;

import com.tutorialspoint.service.HelloWorld;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.jms.spec.JMSSpecConstants;

public final class ClientJMS {
   private static final String JMS_ENDPOINT_URI =
   "jms:queue:test.cxf.jmstransport.queue?timeToLive=1000"
   + "&jndiConnectionFactoryName=ConnectionFactory"
   + "&jndiInitialContextFactory"
   + " = org.apache.activemq.jndi.ActiveMQInitialContextFactory"
   + "&jndiURL = tcp://localhost:61616";

   public static void main(String[] args) throws Exception {
      JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
      factory.setTransportId(JMSSpecConstants.SOAP_JMS_SPECIFICATION_TRANSPORTID);
      factory.setAddress(JMS_ENDPOINT_URI);
      HelloWorld client = factory.create(HelloWorld.class);
      String reply = client.sayHi("TutorialsPoint");
      System.out.println(reply);
      System.exit(0);
   }
}

Apache CXF — Заключение

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

WSDL предоставляет XML-представление вашего интерфейса службы. Вы использовали инструмент wsdl2java для создания интерфейсов Java из WSDL и, наконец, написали сервер и клиент, используя созданные интерфейсы. В руководстве также кратко рассказывается, как использовать CXF в приложении веб-службы RESTful. Наконец, мы также обсудили, как CXF можно использовать с JMS. Теперь вы можете обратиться к CXF-образцам для дальнейшего изучения.

Примечание . Весь исходный код проекта можно загрузить здесь.