Apache CXF z WSDL First

Opracowana przez Ciebie aplikacja CXF-POJO skutkuje bardzo ścisłym połączeniem między klientem a serwerem. Zapewnienie bezpośredniego dostępu do interfejsu usługi może również stanowić poważne zagrożenie bezpieczeństwa. W związku z tym zwykle pożądane jest rozdzielenie między klientem a serwerem, co można osiągnąć za pomocą WSDL (język opisu usług sieci Web).

Interfejs usługi sieciowej piszemy w dokumencie WSDL opartym na języku XML. Użyjemy narzędzia do mapowania tego WSDL na interfejsy Apache CXF, które są następnie implementowane i używane przez nasze aplikacje klienckie i serwerowe. Aby zapewnić odsprzęganie, preferowanym sposobem jest rozpoczęcie od WSDL. W tym celu musisz najpierw nauczyć się nowego języka - WSDL. Pisanie WSDL wymaga ostrożnego podejścia i byłoby lepiej, gdybyś mógł trochę zrozumieć ten temat, zanim zaczniesz nad nim pracować.

W tej lekcji zaczniemy od zdefiniowania interfejsu usługi sieciowej w dokumencie WSDL. Dowiemy się, jak używać CXF do tworzenia aplikacji serwerowych i klienckich począwszy od WSDL. Utrzymamy prostą aplikację, skupiając się na wykorzystaniu CXF. Po utworzeniu aplikacji serwerowej opublikujemy ją pod żądanym adresem URL za pomocą wbudowanej klasy CXF.

Najpierw opiszmy WSDL, którego będziemy używać.

WSDL dla HelloWorld

Usługa sieciowa, którą zamierzamy zaimplementować, będzie miała jedną metodę internetową o nazwie greetings który akceptuje stringparametr przechowujący nazwę użytkownika i zwraca wiadomość tekstową do dzwoniącego po dołączeniu wiadomości pozdrowienia do nazwy użytkownika. Kompletny WSDL pokazano poniżej -

//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>

Zauważ, że napisanie poprawnego składniowo wsdl zawsze było wyzwaniem dla programistów; istnieje wiele narzędzi i edytorów online do tworzenia wsdl. Te edytory pytają o nazwy komunikatów, które chcesz zaimplementować, wraz z parametrami, które chcesz przekazać w wiadomości, oraz typem komunikatu zwrotnego, który ma otrzymać aplikacja kliencka. Jeśli znasz składnię wsdl, możesz ręcznie zakodować cały dokument lub użyć jednego z edytorów do stworzenia własnego.

W powyższym wsdl zdefiniowaliśmy pojedynczą wiadomość o nazwie greetings. Wiadomość zostanie dostarczona do wywoływanej usługiHelloWorldService czyli o godz http://localhost:9090/HelloServerPort.

W ten sposób przejdziemy teraz do rozwoju serwera. Przed opracowaniem serwera musimy wygenerować interfejs Apache CXF do naszej usługi internetowej. Należy to zrobić z podanego wsdl. Aby to zrobić, użyj narzędzia o nazwiewsdl2java.

Wtyczka wsdl2java

Ponieważ będziemy używać mavena do budowania projektu, będziesz musiał dodać następującą wtyczkę do pom.xml plik.

<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>

Zauważ, że określamy lokalizację wsdl plik jako src/main/resources/Hello.wsdl. Będziesz musiał upewnić się, że tworzysz odpowiednią strukturę katalogów dla swojego projektu i dodajesz wcześniej pokazanąhello.wsdl plik do określonego folderu.

Plik wsdl2javaplugin skompiluje ten wsdl i utworzy klasy Apache CXF w predefiniowanym folderze. Pełna struktura projektu jest pokazana tutaj, aby ułatwić odniesienie.

Teraz jesteś gotowy do utworzenia serwera przy użyciu wsdl2javawygenerowane klasy. Klasy utworzone przez wsdl2java pokazano na poniższym rysunku -

Wygenerowany interfejs usługi

Na liście wygenerowanych klas pewnie zauważyłeś, że jedną z nich jest interfejs Apache CXF - to jest HelloWorldPortType.java. Sprawdź ten plik w swoim edytorze kodu. Zawartość pliku jest pokazana tutaj, aby ułatwić odniesienie -

//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
   );
}

Zauważ, że interfejs zawiera metodę o nazwie greetings. To był typ wiadomości w naszym wsdl. Plikwsdl2javanarzędzie dodało tę metodę do wygenerowanego interfejsu. Teraz możesz zrozumieć, że niezależnie od komunikatów, które napiszesz w swoim wsdl, odpowiednia metoda zostanie wygenerowana w interfejsie.

Teraz Twoim zadaniem byłoby zaimplementowanie wszystkich tych metod odpowiadających różnym komunikatom, które zdefiniowałeś w swoim wsdl. Zauważ, że we wcześniejszym przykładzie Apache CXF-First zaczynaliśmy od interfejsu Apache CXF dla naszej usługi internetowej. W tym przypadku interfejs Apache CXF jest tworzony z wsdl.

Implementacja interfejsu usługi

Implementacja interfejsu usługi jest banalna. Pełną implementację przedstawia poniższa lista -

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

Kod implementuje jedyną metodę interfejsu o nazwie greetings. Metoda przyjmuje jeden parametrstring type, dołącza do niego wiadomość „hi” i zwraca wynikowy ciąg do wywołującego.

Następnie napiszemy aplikację serwerową.

Developing Server

Tworzenie aplikacji serwerowej jest po raz kolejny banalne. Tutaj użyjemy dostarczonego CXFEndpointklasy, aby opublikować naszą usługę. Odbywa się to w następujących dwóch wierszach kodu -

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

Najpierw tworzymy obiekt naszej klasy implementatora usługi - HelloWorldImpl. Następnie przekazujemy to odwołanie jako drugi parametr dopublishmetoda. Pierwszym parametrem jest adres, pod którym usługa jest publikowana - klienci używaliby tego adresu URL, aby uzyskać dostęp do usługi. Pełne źródło aplikacji serwerowej jest podane tutaj -

//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);
   }
}

Aby zbudować tę klasę serwerów, musisz dodać profil kompilacji w swoim pom.xml. Jest to pokazane poniżej -

<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>

Zwróć uwagę, że w pełni kwalifikowana nazwa Serverklasa jest określona w konfiguracji. Ponadto tag zależności określa, że ​​będziemy używać wbudowanego serwera WWW molo do wdrożenia naszej aplikacji serwerowej.

Wdrażanie serwera

Na koniec, aby wdrożyć aplikację serwera, będziesz musiał dokonać jeszcze jednej modyfikacji w pom.xml, aby skonfigurować aplikację jako aplikację internetową. Kod, który musisz dodać do swojegopom.xml podano poniżej -

<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>

Przed wdrożeniem aplikacji musisz dodać do projektu jeszcze dwa pliki. Są one pokazane na poniższym zrzucie ekranu -

Te pliki są plikami w standardzie CXF, które definiują mapowanie CXFServlet. Kod wweb.xml plik jest pokazany tutaj do szybkiego odniesienia -

//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>

w cxf-servlet.xmldeklarujesz właściwości punktu końcowego usługi. Jest to pokazane w poniższym fragmencie kodu -

<beans ...>
   <jaxws:endpoint xmlns:helloworld = "http://tutorialspoint.com/"
      id="helloHTTP"
      address = "http://localhost:9090/HelloServerPort"
      serviceName = "helloworld:HelloServiceService"
      endpointName = "helloworld:HelloServicePort">
   </jaxws:endpoint>
</beans>

Tutaj definiujemy identyfikator dla naszego punktu końcowego usługi, adres, pod którym usługa będzie dostępna, nazwę usługi i nazwę punktu końcowego. Teraz wiesz, w jaki sposób Twoja usługa jest kierowana i przetwarzana przez serwlet CXF.

Ostateczna wersja pom.xml

Plik pom.xmlzawiera jeszcze kilka zależności. Zamiast opisywać wszystkie zależności, zamieściliśmy poniżej ostateczną wersję 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>

Zwróć uwagę, że zawiera on również profil do budowania klienta, którego nauczymy się wkrótce w dalszych sekcjach.

Uruchamianie usługi HelloWorld

Teraz możesz uruchomić aplikację internetową. W oknie poleceń uruchom skrypt kompilacji za pomocą następującego polecenia.

mvn clean install

Spowoduje to wygenerowanie odpowiednich klas Apache CXF z pliku wsdl, skompilowanie klas Apache CXF, wdrożenie serwera na wbudowanym serwerze molo i uruchomienie aplikacji.

Na konsoli pojawi się następujący komunikat -

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

Tak jak poprzednio, możesz przetestować serwer, otwierając adres URL serwera w przeglądarce.

Ponieważ nie określiliśmy żadnej operacji, tylko komunikat o błędzie jest zwracany do przeglądarki przez naszą aplikację. Teraz spróbuj dodać?wsdl do adresu URL, a zobaczysz następujący wynik -

Więc nasza aplikacja serwerowa działa zgodnie z oczekiwaniami. Możesz używać klienta SOAP, takiego jakPostman opisane wcześniej w celu dalszego przetestowania usługi.

Następną częścią tego samouczka jest napisanie klienta korzystającego z naszej usługi.

Klient rozwijający się

Napisanie klienta w aplikacji CXF jest tak samo ważne jak napisanie serwera. Oto kompletny kod dla klienta, który zasadniczo składa się tylko z trzech wierszy, reszta wierszy po prostu drukuje informacje o usłudze dla użytkownika.

//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")));
   }
}

Tutaj po prostu tworzymy wystąpienie naszej usługi HelloWorldService, uzyskaj jego port, dzwoniąc getHelloWorldPort metoda, a następnie przekaż nasz plik greetingswiadomość do niego. Uruchom klienta, a zobaczysz następujące dane wyjściowe -

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

Do tej pory nauczyłeś się, jak używać CXF z architekturami Apache CXF-First i WSDL-First. W podejściu Apache CXF-First użyłeś POJO zServerFactoryBeanz bibliotek CXF, aby utworzyć serwer. Aby utworzyć klienta, którego użyłeśClientProxyFactoryBeanklasa z biblioteki CXF. W podejściu WSDL-First użytoEndpointclass, aby opublikować usługę pod żądanym adresem URL i określonym implementatorem. Możesz teraz rozszerzyć te techniki, aby zintegrować różne protokoły i transporty.