使用apache CXF开发第一个Web服务

Tutorial to develop Contract First webservice using CXF

我们要使用apache CXF完成下面这个Web服务:


<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name=
"EmpWorkHours" targetNamespace="http://ts.com/empwork" xmlns:tns="http://ts.com/empwork" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:emp="http://ts.com/empwork/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<schema targetNamespace=
"http://ts.com/empwork/types" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://ts.com/empwork/types" elementFormDefault="qualified">
<xsd:element name=
"EmpWorkHoursRequest" type="emp:EmpWorkHoursRequestType"/>
<xsd:element name=
"EmpWorkHoursResponse" type="emp:EmpWorkHoursResultType"/>
<xsd:complexType name=
"EmpWorkHoursRequestType">
<xsd:sequence>
<xsd:element name=
"empid" type="xsd:string"/>
<xsd:element name=
"year" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name=
"EmpWorkHoursResultType">
<xsd:sequence>
<xsd:element name=
"empid" type="xsd:string"/>
<xsd:element name=
"year" type="xsd:integer"/>
<xsd:element name=
"name" type="xsd:string"/>
<xsd:element name=
"workhours" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</schema>
</wsdl:types>
<wsdl:message name=
"request">
<wsdl:part element=
"emp:EmpWorkHoursRequest" name="in"/>
</wsdl:message>
<wsdl:message name=
"response">
<wsdl:part element=
"emp:EmpWorkHoursResponse" name="out"/>
</wsdl:message>
<wsdl:portType name=
"EmpWorkHours">
<wsdl:operation name=
"getWorkHours">
<wsdl:input message=
"tns:request" name="workHoursRequest"/>
<wsdl:output message=
"tns:response" name="workHoursResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name=
"EmpWorkHours_SOAPBinding" type="tns:EmpWorkHours">
<soap:binding style=
"document" transport="http://schemas.xmlsoap.org/soap/
http
"/>
<wsdl:operation name=
"getWorkHours">
<soap:operation soapAction=
"" style="document"/>
<wsdl:input name=
"workHoursRequest">
<soap:body use=
"literal"/>
</wsdl:input>
<wsdl:output name=
"workHoursResponse">
<soap:body use=
"literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name=
"SOAPService">
<wsdl:port binding=
"tns:EmpWorkHours_SOAPBinding" name="EmpWorkHoursWS">
<soap:address location=
"http://localhost:8090/cxfcontractfirstwebapp/services/
EmpWorkHoursWS
"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>


首先创建一个Maven pom.xml如下:


<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/
maven-v4_0_0.xsd
">
<modelVersion>4.0.0</modelVersion>
<groupId>com.thea</groupId>
<artifactId>cxfcontractfirstwebapp</artifactId>
<packaging>war</packaging>
<version>0.1</version>
<name>cxfcontractfirstwebapp Maven Webapp</name>
<url>http:
//maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.1.2</version>
</dependency>
<!-- Jetty is needed if you're are not using the CXFServlet -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
<build>
<finalName>cxfcontractfirstwebapp</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<!-- wsdl generator plugin-->
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>./src/main/java</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>E:\javacode\nbcodepart2\cxfcontractfirstwebapp\src\main\wsdl\empworkhours.wsdl</wsdl>
<extraargs>
<extraarg>-server</extraarg>
<extraarg>-impl</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>


在我们的Javaf服务类上加上CXF的元注解 Annotation:


package com.ts.empwork;
import java.math.BigInteger;
import java.util.logging.Logger;
[b]@javax.jws.WebService(serviceName = "SOAPService",
portName =
"EmpWorkHoursWS",
targetNamespace =
"http://ts.com/empwork",
wsdlLocation =
"file:/E:/javacode/nbcodepart2/cxfcontractfirstwebapp/src/main/wsdl/
empworkhours.wsdl
",
endpointInterface =
"com.ts.empwork.EmpWorkHours")[/b]
public class EmpWorkHoursImpl implements EmpWorkHours {
private static final Logger LOG =
Logger.getLogger(EmpWorkHoursImpl.class.getName());

//业务方法代码
public com.ts.empwork.types.EmpWorkHoursResultType
getWorkHours(com.ts.empwork.types.EmpWorkHoursRequestType in) {
LOG.info(
"Executing operation getWorkHours");
System.out.println(in);
try {
com.ts.empwork.types.EmpWorkHoursResultType _return = new
com.ts.empwork.types.EmpWorkHoursResultType();
//The below data will be fetched from a datasource. To keep the example simple
//we set hard coded values here
_return.setEmpid(in.getEmpid());
_return.setYear(in.getYear());
_return.setName(
"Karthik");
_return.setWorkhours(new BigInteger(
"1800"));
return _return;
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
}

使用Maven编译后将产生客户端和服务器端的Web服务代码和配置。

CXF和Spring能够无缝结合在一起(所谓无缝其实也是CXF因为在Spring后面出来,为其做了一个转换,如果CXF
在Spring前面出来,然后不需CXF添加新配置和功能,就和Spring整合在一起,这才叫无侵入性的无缝整合,让
别人为你做特别接口,就是你侵入了别人,大家都依赖JVM才是最大的公平和松耦合和无侵入性)

配置Web.xml如下:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/
javaee/web-app_2_5.xsd">
<display-name>cxfcontractfirstwebapp</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:cxf.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
</web-app>

在Maven的 projectroot/src/main/resources目录下创建一个Spring的CXF.xml配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id="EmpWorkHours"
implementor="com.ts.empwork.EmpWorkHoursImpl"
address="/EmpWorkHoursWS">
<jaxws:properties>
</jaxws:properties>
</jaxws:endpoint>
</beans>

部署到Web服务器中,访问 http://localhost:8090/cxfcontractfirstwebapp/services。

个人评价:回想起2006年我们就能够用JBuilder可视化开发工具拖拉一个POJO服务,JBuilder就为我们生成Web服务的配置。
多么简单,敢情开源社区折腾这么多年,添加了apache CXF 以及Spring,和Maven,只是重走了一篇回头路,
好像还没有原来的方便,NetBeans还是提供这个可视化拖拉功能,可惜依赖它的glassfish,再次为JBuilder消失惋惜啊,
用户在工业界和开源社区之间少了一个中间选择。
[该贴被banq于2009-08-30 13:32修改过]