《Apache CXF开发Web Service 理解CXF Frontends之Code-First》一文提到Code-First和Contract-First两种不同的方式,这里将介绍Contract-First的使用。如果使用Contract-First的开发方式,开发者首先准备好WSDL文档,通过CXF提供的工具wsdl2java来生成代码。这个工具在%CXF-HOME%/bin目录中。Contract-First需要完成的工作有:
生成服务组件
实现服务方法
发布Web Service
开发客户端
使用《Apache CXF开发Web Service 理解CXF Frontends之Code-First》中生成的WSDL文档,即启动mvn test –Pserve后,访问http://localhost:8080/OrderProcess?wsdl所看到的内容。现在是要把操作倒过去,通过这个WSDL来生成SEI。
xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="OrderProcessService" targetNamespace="http://order.demo/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://order.demo/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://order.demo/" xmlns:tns="http://order.demo/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="processOrder" type="tns:processOrder" />
<xs:element name="processOrderResponse" type="tns:processOrderResponse" />
<xs:complexType name="processOrder">
<xs:sequence>
<xs:element minOccurs="0" name="arg0" type="tns:order" />
xs:sequence>
xs:complexType>
<xs:complexType name="order">
<xs:sequence>
<xs:element minOccurs="0" name="customerID" type="xs:string" />
<xs:element minOccurs="0" name="itemID" type="xs:string" />
<xs:element name="price" type="xs:double" />
<xs:element name="qty" type="xs:int" />
xs:sequence>
xs:complexType>
<xs:complexType name="processOrderResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="xs:string" />
xs:sequence>
xs:complexType>
xs:schema>
wsdl:types>
<wsdl:message name="processOrderResponse">
<wsdl:part element="tns:processOrderResponse" name="parameters">
wsdl:part>
wsdl:message>
<wsdl:message name="processOrder">
<wsdl:part element="tns:processOrder" name="parameters">
wsdl:part>
wsdl:message>
<wsdl:portType name="OrderProcess">
<wsdl:operation name="processOrder">
<wsdl:input message="tns:processOrder" name="processOrder">
wsdl:input>
<wsdl:output message="tns:processOrderResponse" name="processOrderResponse">
wsdl:output>
wsdl:operation>
wsdl:portType>
<wsdl:binding name="OrderProcessServiceSoapBinding" type="tns:OrderProcess">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="processOrder">
<soap:operation soapAction="" style="document" />
<wsdl:input name="processOrder">
<soap:body use="literal" />
wsdl:input>
<wsdl:output name="processOrderResponse">
<soap:body use="literal" />
wsdl:output>
wsdl:operation>
wsdl:binding>
<wsdl:service name="OrderProcessService">
<wsdl:port binding="tns:OrderProcessServiceSoapBinding" name="OrderProcessPort">
<soap:address location="http://localhost:8080/OrderProcess" />
wsdl:port>
wsdl:service>
wsdl:definitions>
生成服务组件
将准备好的WSDL文档命名为OrderProcess.wsdl。文档的内容与使用JAX-WS规范的JAVA组件对应。
WSDL element |
Java component |
targetNamespace attribute of the targetNamespace="http://order.demo/" |
Java package(demo.order) |
<wsdl:portType name="OrderProcess"> |
Java Service Endpoint Interface (SEI) OrderProcess |
<wsdl:operation name="processOrder"> |
Java methods processOrder |
<wsdl:service name="OrderProcessService"> |
Service class OrderProcessService |
|
Service operation parameters |
关于wsdl2java工具的使用请参考:
http://cxf.apache.org/docs/wsdl-to-java.html
http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html
这里将介绍Maven 的插件 cxf-codegen-plugin 来生成代码的方式。《Apache CXF开发Web Service 理解CXF Frontends之Code-First》文中提到的pom.xml添加cxf-codegen-plugin。
<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.0modelVersion>
<groupId>org.dcb.cxfbook.ch03groupId>
<artifactId>contractfirstartifactId>
<version>1.0version>
<packaging>jarpackaging>
<name>contractfirstname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<cxf.version>2.2.3cxf.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.cxfgroupId>
<artifactId>cxf-rt-frontend-jaxwsartifactId>
<version>${cxf.version}version>
dependency>
<dependency>
<groupId>org.apache.cxfgroupId>
<artifactId>cxf-rt-transports-httpartifactId>
<version>${cxf.version}version>
dependency>
<dependency>
<groupId>org.apache.cxfgroupId>
<artifactId>cxf-rt-transports-http-jettyartifactId>
<version>${cxf.version}version>
dependency>
dependencies>
<build>
<finalName>contractfirstfinalName>
<plugins>
<plugin>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.5source>
<target>1.5target>
configuration>
plugin>
<plugin>
<groupId>org.apache.cxfgroupId>
<artifactId>cxf-codegen-pluginartifactId>
<version>${cxf.version}version>
<executions>
<execution>
<id>generate-sourcesid>
<phase>generate-sourcesphase>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>src/main/resources/OrderProcess.wsdlwsdl>
wsdlOption>
wsdlOptions>
configuration>
<goals>
<goal>wsdl2javagoal>
goals>
execution>
executions>
plugin>
plugins>
build>
<profiles>
<profile>
<id>serverid>
<build>
<defaultGoal>testdefaultGoal>
<plugins>
<plugin>
<groupId>org.codehaus.mojogroupId>
<artifactId>exec-maven-pluginartifactId>
<executions>
<execution>
<phase>testphase>
<goals>
<goal>javagoal>
goals>
<configuration>
<mainClass>demo.order.OrderProcessServermainClass>
configuration>
execution>
executions>
plugin>
plugins>
build>
profile>
<profile>
<id>clientid>
<build>
<defaultGoal>testdefaultGoal>
<plugins>
<plugin>
<groupId>org.codehaus.mojogroupId>
<artifactId>exec-maven-pluginartifactId>
<executions>
<execution>
<phase>testphase>
<goals>
<goal>javagoal>
goals>
<configuration>
<mainClass>demo.order.client.ClientmainClass>
configuration>
execution>
executions>
plugin>
plugins>
build>
profile>
profiles>
project>
执行命令:
cd contractfirst
mvn generate-sources
Maven cxf-codegen-plugin会为你自动调用CXF 中wsdl2java工具。可能初学Maven的朋友不大理解,这里简单介绍cxf-codegen-plugin的使用。在build.plugins.plugin中添加cxf-codegen-plugin。<wsdl>src/main/resources/OrderProcess.wsdlwsdl>指明要转换的WSDL文档。<phase>generate-sourcesphase>指明执行的命令。<goal>wsdl2javagoal>指明执行命令所包含的工作。
对于Goal和Phase的关系,在《Maven中的几个重要概念(二):lifecycle, phase and goal》一文中有详细的介绍。这里摘选Goal和Phase的内容:
Maven定义了一系列Best Practice,将关联的Phase组合在一起,即执行一个phase会执行某个liefcycle所有的phase。Goal是独立的,可以绑定到多个phase中,也可以不绑定。从这方面讲,phase就是goal的容器,实际被执行的是goal。
在本文中执行generate-sources这个phase,其实是执行cxf-codegen-plugin中的<goal>wsdl2javagoal>
对于Maven的生命周期,请看《Maven生命周期详解》。
跑题了半天,让我们看看这mvn generate-sources到底生成了什么内容:
JAXB输入/输出消息类。wsdl2java类会分别生成JAVA输入/输出消息组件。本例中将会生成ProcessOrder作为输入类,生成ProcessOrderResponse作为输出类,还会根据<xs:complexType name="order">生成Order类。
服务接口。本例中服务接口为OrderProcess。
服务实现类。本例中提供了继承自Service接口的实现类OrderProcessService。我们可以修改这个类来实现功能。
这些类都在包demo.order中。wsdl2java工具从targetNamespace="http://order.demo/"生成包名,也就是http://order.demo/除去http://后倒写。
如果修改pom.xml,添加如下内容,将会生成OrderProcessImpl.java(示例的实现服务类)和OrderProcess_OrderProcessPort_Server.java(CXF提供的独立的服务器)。
<wsdlOption>
<wsdl>src/main/resources/OrderProcess.wsdlwsdl>
<extraargs>
<extraarg>-serverextraarg>
<extraarg>-implextraarg>
<extraarg>-verboseextraarg>
extraargs>
wsdlOption>
JAXB 输入/输出消息类
ProcessOrder, ProcessOrderResponse和Order这三个类代表Web Service操作类。这几个类有着各种JAXB注解。ProcessOrder和 ProcessOrderResponse用来表示Request和Response。Request拥有出入参数引用,而Response着拥有输出参数引用。
为了理解Request和Response的概念,来看看Web Service将会提交什么样的SOAP Request消息。
<arg0>
arg0>
processOrder映射为Web Service中的方法processOrder。子元素arg0代表着SOAP payload,映射为输入参数Order。CXF会自动将arg0转换为Order对象,并执行processOrder方法。
服务接口
OrderProcess是SEI,定义了processOrder方法。
@WebService(targetNamespace = "http://order.demo/", name = "OrderProcess")
@XmlSeeAlso({ObjectFactory.class})
public interface OrderProcess {
@WebResult(name = "return", targetNamespace = "")
@RequestWrapper(localName = "processOrder", targetNamespace = "http://order.demo/", className = "demo.order.ProcessOrder")
@ResponseWrapper(localName = "processOrderResponse", targetNamespace = "http://order.demo/", className = "demo.order.ProcessOrderResponse")
@WebMethod
public java.lang.String processOrder(
@WebParam(name = "arg0", targetNamespace = "")
demo.order.Order arg0
);
}
@WebService定义了这个接口是SEI。
@Xml SeeAlso通知JAXB在执行数据绑定是包含ObjectFactory。
@RequestWrapper包含了输入消息。
@ResponseWrapper包含了输出消息。
@WebResult指明返回的类型。
@WebMethod指明这是个服务方法。
@WebParam指明参数。
运行Web Service
《Apache CXF开发Web Service 理解CXF Frontends之Code-First》一文执行过程类似。
cd contractfirst
#启动server,显示Server ready...消息
mvn test –Pserver
#执行client,显示The order ID is ORD1234
mvn test -Pclient
参考内容
《Maven中的几个重要概念(二):lifecycle, phase and goal》
《Maven生命周期详解》
http://cxf.apache.org/docs/wsdl-to-java.html
http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html
http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html