本文以CXF 2.6.x为例,会用到jsr311.jar 。当前CXF最新版本为3.x,依赖jsr版本也有所不同,且Spring配置文件中也不再需要配置:<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />。
在做版本升级时,需要留以上细节。
现在开始以CXF2.6.x做一些Demo。
一、首先我们搭建一个Maven Project,其中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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>abc-api</artifactId> <packaging>war</packaging> <version>${global.version}</version> <parent> <groupId>com.abc.module</groupId> <artifactId>abc-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <dependencies> <dependency> <groupId>javax.ws.rs</groupId> <artifactId>jsr311-api</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxrs</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>org.codehaus.jettison</groupId> <artifactId>jettison</artifactId> <version>1.3.5</version> </dependency> <dependency> <groupId>axis</groupId> <artifactId>axis</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>org.codehaus.woodstox</groupId> <artifactId>stax2-api</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>org.jbarcode</groupId> <artifactId>jbarcode</artifactId> <version>0.2.8</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> </build> </project>
二、配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>fsp-api</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:application.xml</param-value> </context-param> <!-- spring context listener --> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- CXF --> <servlet> <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> </web-app>
三、创建Webservice对外业务接口
import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; @WebService public interface ILogisticsWsApi { /** * @param xmlParam * @return xml string */ @WebMethod(operationName = "itemConfirm") public String itemConfirm(@WebParam String xmlParam); }
四、实现Webservice接口
public class LogisticsWsApiImpl implements ILogisticsWsApi { private Logger log = LoggerFactory.getLogger(getClass()); @Override public String itemConfirm(String xmlParam) { // TODO Auto-generated method stub log.debug("itemConfirm xml param : " + xmlParam); LogisticsMessage logisticsMessage = LogisticsFactory.createItemConfirmRequest(); logisticsMessage.decode(xmlParam); // to do something ... return response; } }
五、配置Spring xml,让Webservice提供服务
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" 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 http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.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" /> <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/> <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> <jaxws:endpoint id="logisticsWsApiServiceContainer" implementor="com.abc.api.service.LogisticsWsApiImpl" address="/logisticsWsApi" > <jaxws:inInterceptors> <ref bean="loggingInInterceptor"/> </jaxws:inInterceptors> <jaxws:outInterceptors> <ref bean="loggingOutInterceptor"/> </jaxws:outInterceptors> </jaxws:endpoint> </beans>
至此,Webservice服务端的代码就完成了,启动Web server即可以对外提供服务了。
假设你当前的Maven Project名字为:abc-api,那么实际访问Webservice 的Address就为:http://ip:port/abc-api/services/logisticsWsApi?wsdl
六、我们编写一个JunitTester测试前面的Webservice接口
import static org.junit.Assert.*; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.abc.warehouse.service.ILogisticsWsApi; public class LogisticsWsApiTester { private JaxWsProxyFactoryBean wsFactory; private String address = "http://localhost:8080/abc-api/services/logisticsWsApi"; /** * * @throws java.lang.Exception */ @Before public void setUp() throws Exception { wsFactory = new JaxWsProxyFactoryBean(); wsFactory.setAddress(address); wsFactory.setServiceClass(ILogisticsWsApi.class); } /** * * @throws java.lang.Exception */ @After public void tearDown() throws Exception { wsFactory = null; } /** * Test method for {@link com.abc.api.service.LogisticsWsApiImpl#itemConfirm(java.lang.String)}. */ @Test public void testItemConfirm() { // fail("Not yet implemented"); String xmlParam = "Hello JaxWs , 欢迎"; ILogisticsWsApi logisticsWsApi = (ILogisticsWsApi) wsFactory.create(); String recvMessage = logisticsWsApi.itemConfirm(xmlParam); assertEquals(recvMessage, null); }
当然,我们也可以把JaxWsProxyFactoryBean用Spring类配置或直接在Spring中配置jaxws:client
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" 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 http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.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:client id="logisticsWsApi" serviceClass="com.abc.warehouse.service.ILogisticsWsApi" address="${logisticsWsApiAddress}"/> </beans>
<bean id="logisticsWsApi" class="com.abc.warehouse.service.ILogisticsWsApi" factory-bean="clientFactory" factory-method="create" /> <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="com.abc.warehouse.service.ILogisticsWsApi" /> <property name="address" value="${logisticsWsApiAddress}" /> <!-- http://localhost:8080/abc-api/services/logisticsWsApi --> </bean>
到这里,我们就已经完成了Webservice服务端和客户端的开发。
其中,在日志拦截器LoggingInInterceptor类的logging(Logger logger, Message message)函数中,在输出日志时可能会遇到乱码问题,这个乱码不会影响实际的业务操作。
如果要修正这里的乱码,可以通过重载该函数来处理解码中文的问题。修改方法很简单,详情见:《Apache cxf JaxRs基本应用》。