本文主要涉及的webservice采用SOAP协议、采用JAX-WS作为前端、JAXB数据绑定。需要加入以下依赖:
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-bindings-soap</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-databinding-jaxb</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>2.7.0</version> </dependency>
与之前基于JAX-WS的webservice一致,作为前端并不需要有任何修改。在这个例子中包含了传递String、自定义对象、Map等
@WebService(serviceName = "cxfServer") public class CXFServiceImpl implements CXFService { @Override @WebMethod public String sayHello(String name) { return "Hello, " + name + ", from CXF"; } @Override @WebMethod @WebResult @XmlJavaTypeAdapter(value = MapAdapter.class) public Map<String, Person> queryPerson() { Map<String, Person> map = new HashMap<String, Person>(); map.put("p1", new Person("robin", "robin_123")); map.put("p2", new Person("ace", "ace_456")); return map; } @Override @WebMethod public void savePerson(@WebParam List<Person> list) { if (list != null && !list.isEmpty()) { for (Person person : list) { System.out.println(ToStringBuilder.reflectionToString(person, ToStringStyle.SHORT_PREFIX_STYLE)); } } } }
注意对传递Map,在JAX-WS是不能直接传递,需要作为一个包装类传递。而在CXF中则可以直接传递,这里还是采用JAXB作为解析对象故这里的MapAdapter与之前的一致.见这里
1、jaxwsserver
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean(); factory.setServiceClass(CXFServiceImpl.class); factory.setAddress("http://localhost:8080/service/helloCxfService"); //optional: set in interceptors factory.getInInterceptors().add(new LoggingInInterceptor()); //optional: set out interceptors factory.getOutInterceptors().add(new LoggingOutInterceptor()); factory.create();
由于采用jetty作为默认的Server的实现,需要加入
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>2.7.0</version> </dependency>
运行后即可通过http://localhost:8080/service/helloCxfService?wsdl查看发布结果。或者可以通过这样测试
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(CXFService.class); factory.setAddress("http://localhost:8080/service/helloCxfService"); CXFService server = (CXFService) factory.create();
2、spring集成的几种方式
需要在spring的配置文件加入相应的schema及location:
xmlns:jaxws="http://cxf.apache.org/jaxws" 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" />
打开位于cxf-rt-frontend-jaxws-2.7.0.jar/schemas/jaxws.xsd文件,我们查看定义了三种方式:
jaxws:endpoint jaxws:server jaxws:client
前两者用来申明发布server,后者作为客户端的配置。下面来看看与spring继承的几种方式:
1、采用jaxws:server配置
<!-- 采用jaxws:server方式 --> <jaxws:server id="helloCxf" serviceClass="org.ws.server.cxf.chap1.CXFService" address="http://localhost:8080/service/helloCxf"> <jaxws:serviceBean> <bean class="org.ws.server.cxf.chap1.impl.CXFServiceImpl" /> </jaxws:serviceBean> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" /> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> </jaxws:outInterceptors> </jaxws:server>这里jaxws:endpoint的配置大同小异,具体参数配置见jaxws.xsd
2、由于采用JAX-WS作为前端,作为对JaxWsServerFactoryBean实例的注入:
<!-- 作为对JaxWsServerFactoryBean的注入 --> <bean id="cxfServiceFactory" class="org.apache.cxf.jaxws.JaxWsServerFactoryBean"> <property name="serviceClass" value="org.ws.server.cxf.chap1.impl.CXFServiceImpl" /> <property name="address" value="http://localhost:8080/service/helloCxf" /> <property name="inInterceptors"> <list> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" /> </list> </property> <property name="outInterceptors"> <list> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> </list> </property> </bean>
针对上面两种配置,可以通过在http://localhost:8080/service/helloCxf?wsdl访问发布成功与否。当然上面的address采用了绝对路径,实际上和web项目的整合只需要指定到相对路径即可。<bean id="helloCxfService" class="org.ws.server.cxf.chap1.impl.CXFServiceImpl"
factory-bean="cxfServiceFactory" factory-method="create" />
<property name="address" value="/helloCxf" />
<servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping>运行后即可通过容器发布的路径访问,如:http://localhost:8080/webservice/service/helloCxf?wsdl
wsdl2java -p org.sample.ws.client.cxf.chap1 -keep -verbose http://localhost:8080/webservice/service/helloCxf?wsdl
<jaxws:client id="helloCxfClient" address="http://localhost:8080/webservice/service/helloCxf" serviceClass="org.sample.ws.client.cxf.chap1.CXFService"> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" /> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> </jaxws:outInterceptors> </jaxws:client>
<!-- 作为对JaxWsProxyFactoryBean的注入 --> <bean id="cxfClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="org.sample.ws.client.cxf.chap1.CXFService" /> <property name="address" value="http://localhost:8080/webservice/service/helloCxf" /> <property name="inInterceptors"> <list> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" /> </list> </property> <property name="outInterceptors"> <list> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> </list> </property> </bean> <bean id="helloCxfService" class="org.sample.ws.client.cxf.chap1.CXFService" factory-bean="cxfClientFactory" factory-method="create" />
ClassPathXmlApplicationContext xmlApplication = new ClassPathXmlApplicationContext("cxf-spring.xml"); CXFService service = (CXFService) xmlApplication.getBean("helloCxfService"); System.out.println(service.sayHello("robin"));
<bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="http://localhost:8080/webservice/service/helloCxf?wsdl" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> <enableAsyncMapping>true</enableAsyncMapping> </bindings> </bindings>在生成客户端的时候需要指定该binding.xml文件
wsdl2java -p org.sample.ws.client.cxf.chap2 -b .\binding.xml -keep -verbose http://localhost:8080/webservice/service/helloCxf?wsdl测试:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(CXFService.class); factory.setAddress("http://localhost:8080/webservice/service/helloCxf"); CXFService server = (CXFService) factory.create(); System.out.println("同步--> server.sayHello(\"robin\"): " + server.sayHello("robin")); Response<SayHelloResponse> response = server.sayHelloAsync("robin"); while (!response.isDone()) { System.out.println("异步调用......"); } System.out.println("异步: " + response.get().getReturn());