使用WSDL的Apache CXF

您开发的CXF-POJO应用程序导致客户端和服务器之间的紧密耦合。直接访问服务接口也会造成严重的安全威胁。因此,通常需要在客户端和服务器之间实现解耦,这是通过使用WSDL(Web服务描述语言)实现的。

我们在基于XML的WSDL文档中编写Web服务接口。我们将使用一个工具将此WSDL映射到Apache CXF接口,然后由我们的客户端和服务器应用程序实现和使用这些接口。为了提供去耦,从WSDL开始是首选方法。为此,您需要首先学习一种新的语言-WSDL。编写WSDL需要谨慎的方法,如果您在开始工作之前对此有所了解,那会更好。

在本课程中,我们将从在WSDL文档中定义Web服务接口开始。我们将学习如何使用CXF从WSDL开始创建服务器和客户端应用程序。我们将使应用程序简单易行,以保持对CXF使用的关注。创建服务器应用程序后,我们将使用内置的CXF类将其发布到所需的URL。

首先,让我们描述我们将要使用的WSDL。

WSDL for HelloWorld

WebService的,我们要实现将有一个单一的WebMethod叫问候,它接受一个字符串参数保存的用户名和追加的问候消息,在用户名后返回一个字符串消息给调用者。完整的wsdl如下所示-

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

请注意,编写语法正确的wsdl一直是开发人员的挑战。有许多工具和在线编辑器可用于创建wsdl。这些编辑器询问您要实现的消息的名称,以及希望传递给消息的参数,以及希望客户端应用程序接收的返回消息的类型。如果您知道wsdl语法,则可以手工编写整个文档的代码或使用其中一个编辑器创建自己的代码。

在上面的wsdl中,我们定义了一条称为greetings的消息。该消息将传递到运行在http:// localhost:9090 / HelloServerPort的名为HelloWorldService的服务

现在,我们将继续进行服务器开发。在开发服务器之前,我们需要为我们的Web服务生成Apache CXF接口。这将从给定的wsdl完成。为此,请使用名为wsdl2java的工具。

wsdl2java插件

由于我们将使用maven构建项目,因此您需要将以下插件添加到pom.xml文件中。

<plugins>
   <plugin>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-codegen-plugin</artifactId>
      <version>3.3.0</version>
      <executions>
         <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
               <wsdlOptions>
                  <wsdlOption>
                     <wsdl>src/main/resources/hello.wsdl</wsdl>
                     <faultSerialVersionUID> 1 </faultSerialVersionUID>
                  </wsdlOption>
               </wsdlOptions>
            </configuration>
            <goals>
               <goal>wsdl2java</goal>
            </goals>
         </execution>
      </executions>
   </plugin>
</plugins>

请注意,我们将wsdl文件的位置指定为src / main / resources / Hello.wsdl。您将必须确保为项目创建适当的目录结构,并将之前显示的hello.wsdl文件添加到指定的文件夹。

WSDL2Java的插件将编译这个WSDL,并在预先定义的文件夹中创建的Apache CXF类。此处显示了完整的项目结构,以供您随时参考。

使用WSDL的Apache CXF

现在,您准备使用wsdl2java生成的类创建服务器。wsdl2java创建的类如下图所示:

使用WSDL的Apache 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示例中,我们从Web服务的Apache CXF接口开始。在这种情况下,Apache CXF接口是从wsdl创建的。

实施服务接口

服务接口的实现很简单。完整的实现在下面的列表中显示-

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

该代码实现了唯一的接口方法,称为greetings。该方法采用字符串类型的一个参数,在其前面加上“ hi”消息,然后将结果字符串返回给调用方。

接下来,我们将编写服务器应用程序。

开发服务器

开发服务器应用程序再简单不过了。在这里,我们将使用CXF提供的Endpoint类来发布我们的服务。这在以下两行代码中完成-

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

首先,我们创建服务实现程序类HelloWorldImpl的对象。然后,我们将此引用作为第二个参数传递给publish方法。第一个参数是服务发布到的地址-客户端将使用此URL访问服务。服务器应用程序的整个源在这里给出-

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

要构建此服务器类,您将需要在pom.xml中添加一个构建配置文件。这如下所示-

<profile>
   <id>server</id>
   <build>
      <defaultGoal>test</defaultGoal>
      <plugins>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.6.0</version>
            <executions>
               <execution>
                  <phase>test</phase>
                  <goals>
                     <goal>java</goal>
                  </goals>
                  <configuration>
                     <mainClass>
                        com.tutorialspoint.helloworld.Server
                     </mainClass>
                  </configuration>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</profile>

请注意,在配置中指定了Server类的标准名称。另外,dependency标签指定我们将使用嵌入式码头网络服务器来部署我们的服务器应用程序。

部署服务器

最后,要部署服务器应用程序,您将需要在pom.xml中进行另一处修改,以将您的应用程序设置为Web应用程序。您需要添加到pom.xml中的代码如下:

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

在部署应用程序之前,您需要再向项目中添加两个文件。这些显示在下面的屏幕截图中:

使用WSDL的Apache CXF

这些文件是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>

在这里,我们定义了服务端点的ID,可以使用该服务的地址,服务名称和端点名称。现在,您了解了CXF Servlet如何路由和处理服务。

最终的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

这将从您的wsdl生成适当的Apache CXF类,编译您的Apache CXF类,在嵌入式码头服务器上部署服务器并运行您的应用程序。

您将在控制台上看到以下消息-

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

和以前一样,您可以通过在浏览器中打开服务器URL来测试服务器。

使用WSDL的Apache CXF

由于我们未指定任何操作,因此我们的应用程序仅将错误消息返回到浏览器。现在,尝试将?wsdl添加到您的URL中,您将看到以下输出:

使用WSDL的Apache CXF

因此,我们的服务器应用程序正在按预期运行。您可以使用SOAP Client(如先前所述的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.web176.com/}HelloWorldService
wsdl location: file:/Users/drsarang/Desktop/tutorialpoint/cxf-
wsdl/src/main/resources/Hello.wsdl
hi drsarang

到目前为止,您已经了解了如何在Apache CXF-First和WSDL-First体系结构中使用CXF。在Apache CXF-First方法中,将POJO与CXF库中的ServerFactoryBean类一起使用来创建服务器。要创建客户端,请使用CXF库中的ClientProxyFactoryBean类。在WSDL-First方法中,使用Endpoint类在所需的URL和指定的实现者处发布服务。现在,您可以扩展这些技术以集成不同的协议和传输。

作者:terry,如若转载,请注明出处:https://www.web176.com/apachecxf/221.html

(0)
打赏 支付宝 支付宝 微信 微信
terryterry
上一篇 2020年10月22日 下午1:48
下一篇 2020年10月22日 下午2:09

相关推荐

发表回复

登录后才能评论