1、用CXF编写基于Spring的Web service,也是需要分为Server服务器端、Client客户端的。
1.1)、Server端,操作步骤,如下所示:
第一步,创建spring的配置文件beans.xml,在其中配置SEI。
第二步,在web.xml中,配置上CXF的一些核心组件。
1.2、Client端,操作步骤,如下所示:
第一步,生成客户端代码。
第二步,创建客户端的spring配置文件beans-client.xml,并配置。
第三步,编写测试类请求web service。
2、创建一个动态web工程,将apache-cxf-2.5.9\lib目录下面的包添加到此动态工程的lib目录下面,然后Build Path一下的哦。如果要看源代码,需要下载对应的src包的,不然无法进行查看源代码的。
创建web.xml配置文件,如下所示:
1 <?xml version="1.0" encoding="UTF-8"?>2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 5 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 6 id="WebApp_ID" version="2.5">7 <display-name>webServiceCxf_Spring</display-name>8 <welcome-file-list>9 <welcome-file>index.html</welcome-file>
10 <welcome-file>index.jsp</welcome-file>
11 </welcome-file-list>
12
13 <!-- 配置beans.xml -->
14 <context-param>
15 <param-name>contextConfigLocation</param-name>
16 <param-value>classpath:beans.xml</param-value>
17 </context-param>
18 <!-- 应用启动的一个监听器 -->
19 <listener>
20 <listener-class>
21 org.springframework.web.context.ContextLoaderListener
22 </listener-class>
23 </listener>
24
25 <!-- 所有请求都会先经过cxf框架 -->
26 <servlet>
27 <servlet-name>CXFServlet</servlet-name>
28 <servlet-class>
29 org.apache.cxf.transport.servlet.CXFServlet
30 </servlet-class>
31 <load-on-startup>1</load-on-startup>
32 </servlet>
33 <servlet-mapping>
34 <servlet-name>CXFServlet</servlet-name>
35 <url-pattern>/*</url-pattern>
36 </servlet-mapping>
37
38 </web-app>
创建webservice的接口服务,如下所示:
1 package com.bie.webservice.ws;2 3 import javax.jws.WebMethod;4 import javax.jws.WebService;5 6 import com.bie.webservice.bean.Order;7 8 /**9 *
10 * @author
11 *
12 */
13 @WebService
14 public interface OrderWS {
15
16 /**
17 * 根据订单号获取到订单信息
18 *
19 * @param id
20 * @return
21 */
22 @WebMethod
23 public Order getOrderById(int id);
24
25 }
创建webservice的接口服务实现类,如下所示:
1 package com.bie.webservice.ws.impl;2 3 import javax.jws.WebService;4 5 import com.bie.webservice.bean.Order;6 import com.bie.webservice.ws.OrderWS;7 8 /**9 *
10 * @author 项目部署的时候就创建好了webservice服务了。项目启动就自动部署了webservice了。
11 *
12 */
13 @WebService
14 public class OrderWSImpl implements OrderWS {
15
16 /**
17 * 从对象什么时候创建呢,结论,项目部署的时候执行了
18 */
19 public OrderWSImpl() {
20 System.out.println("无参构造器执行,OrderWSImpl......");
21 }
22
23 @Override
24 public Order getOrderById(int id) {
25 System.out.println("Server getOrderById() : " + id);
26 return new Order(1, "大飞机", 999999999.00);
27 }
28
29 }
创建一个是实体类,如下所示:
1 package com.bie.webservice.bean;2 3 /**4 * 5 * @author6 *7 */8 public class Order {9
10 private int id;// 订单编号
11 private String name;// 订单名称
12 private Double price;// 订单价格
13
14 public int getId() {
15 return id;
16 }
17
18 public void setId(int id) {
19 this.id = id;
20 }
21
22 public String getName() {
23 return name;
24 }
25
26 public void setName(String name) {
27 this.name = name;
28 }
29
30 public Double getPrice() {
31 return price;
32 }
33
34 public void setPrice(Double price) {
35 this.price = price;
36 }
37
38 @Override
39 public String toString() {
40 return "Order [id=" + id + ", name=" + name + ", price=" + price + "]";
41 }
42
43 public Order(int id, String name, Double price) {
44 super();
45 this.id = id;
46 this.name = name;
47 this.price = price;
48 }
49
50 }
创建beans.xml配置文件,如下所示:
1 <?xml version="1.0" encoding="UTF-8"?>2 <beans xmlns="http://www.springframework.org/schema/beans"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xmlns:jaxws="http://cxf.apache.org/jaxws"5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd7 http://cxf.apache.org/jaxws 8 http://cxf.apache.org/jaxws">9
10 <!-- 引cxf-2.5.9.jar此包下面的配置,这些配置不在此项目中,cxf的一些核心配置 -->
11 <import resource="classpath:META-INF/cxf/cxf.xml" />
12 <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
13 <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
14
15 <!--
16 jaxws:endpoint标签配置终端。
17 implementor是实现类。
18 address是虚拟地址。
19 -->
20 <jaxws:endpoint id="orderWS"
21 implementor="com.bie.webservice.ws.impl.OrderWSImpl"
22 address="/orderws">
23 <!--
24 <jaxws:inInterceptors>
25 <bean class="com.bie.interceptor.CheckUserInterceptor"></bean>
26 </jaxws:inInterceptors>
27 -->
28 </jaxws:endpoint>
29
30 </beans>
项目结构,如下所示:
然后可以进行发布了,Run as -> Run on Server,启动项目,项目启动就自动部署了webservice了,可以进行访问,如下所示:
访问地址:http://localhost:8080/webServiceCxf_Spring/orderws?wsdl,其中项目名称后面的地址是beans.xml里面配置的address属性的值。
可以使用eclipse自带的web service浏览器进行查看,如下所示:
3、然后,创建一个客户端访问的动态web工程,将apache-cxf-2.5.9\lib目录下面的包添加到此动态工程的lib目录下面,然后Build Path一下的哦。如果要看源代码,需要下载对应的src包的,不然无法进行查看源代码的。此时,还是需要借助java自带的工具来生成客户端的代码,如下所示:
刷新项目,就可以看到生成的代码了,如下所示:
然后创建一个配置文件client-beans.xml,里面需要进行配置webservice的请求地址和所需要生成的动态代理对象。
1 <?xml version="1.0" encoding="UTF-8"?>2 <beans xmlns="http://www.springframework.org/schema/beans"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xmlns:jaxws="http://cxf.apache.org/jaxws"5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd7 http://cxf.apache.org/jaxws http://cxf.apache.org/jaxws">8 9 <!--
10 客户端配置:
11 serviceClass根据此类动态产生接口的代理对象。
12 address是指的是webservice请求的地址。
13 -->
14 <jaxws:client id="orderClient"
15 serviceClass="com.bie.webservice.ws.OrderWS"
16 address="http://localhost:8080/webServiceCxf_Spring/orderws">
17
18 <!-- <jaxws:outInterceptors>
19 <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
20 <bean
21 class="com.bie.webservice.ws.interceptor.AddUserInterceptor">
22 <constructor-arg name="name" value="张姗姗" />
23 <constructor-arg name="password" value="123456" />
24 </bean>
25 </jaxws:outInterceptors> -->
26 </jaxws:client>
27
28 </beans>
最后搞一个客户端的访问类,就可以进行运行了,如下所示:
1 package com.bie.webservice.ws.client;2 3 import org.springframework.context.support.ClassPathXmlApplicationContext;4 5 import com.bie.webservice.ws.Order;6 import com.bie.webservice.ws.OrderWS;7 8 /**9 *
10 * @author 客户端访问webservice的代码
11 *
12 */
13 public class ClientCxfSpring {
14
15 public static void main(String[] args) {
16 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
17 new String[] { "client-beans.xml" });
18 OrderWS orderWS = (OrderWS) context.getBean("orderClient");
19 Order order = orderWS.getOrderById(1);
20 System.out.println(order);
21 }
22
23 }
4、如何在此基础上添加自定义拦截器,步骤如下所示:
第一步,Server端,在beans.xml中,在endpoint中配置上入拦截器。
1 package com.bie.webservice.interceptor;2 3 import javax.xml.namespace.QName;4 5 import org.apache.cxf.binding.soap.SoapMessage;6 import org.apache.cxf.headers.Header;7 import org.apache.cxf.interceptor.Fault;8 import org.apache.cxf.phase.AbstractPhaseInterceptor;9 import org.apache.cxf.phase.Phase;
10 import org.w3c.dom.Element;
11 import org.w3c.dom.Node;
12
13 /**
14 * 查检用户的拦截器
15 *
16 * @author
17 *
18 */
19
20 public class CheckUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
21
22 private static final String name = "张姗姗";
23 private static final String password = "123456";
24
25 public CheckUserInterceptor() {
26 super(Phase.PRE_PROTOCOL);
27 System.out.println("CheckUserInterceptor()");
28 }
29
30 /**
31 * 请求体,服务器端需要解析请求头信息
32 *
33 * <soap:Envelope>
34 * <head>
35 * <zhangsansan>
36 * <name>zhangsansan</name>
37 * <password>123456</password>
38 * </zhangsansan>
39 * </head>
40 * <Body>
41 * <sayHello>
42 * <arg0>张姗姗</arg0>
43 * </sayHello>
44 * </Body>
45 * </soap:Envelope>
46 */
47 @Override
48 public void handleMessage(SoapMessage soapMessage) throws Fault {
49 // 获取到请求头的信息
50 QName qName = QName.valueOf("zhangsansan");
51 // 获取到请求头
52 Header header = soapMessage.getHeader(qName);
53 // 判断是否为空
54 if(header != null) {
55 // 获取到对象,强转为w3c的元素标签
56 Element element = (Element) header.getObject();
57 // 获取到name标签的值
58 Node nameNode = element.getElementsByTagName("name").item(0);
59 // 获取到name的值
60 String nameValue = nameNode.getTextContent();
61 // 获取到pasword标签的值
62 Node passwordNode = element.getElementsByTagName("password").item(0);
63 // 获取到pasword的值
64 String paswordValue = passwordNode.getTextContent();
65 // 开始进行判断
66 if(CheckUserInterceptor.name.equals(nameValue) && CheckUserInterceptor.password.equals(paswordValue)) {
67 System.out.println("Server 通过拦截器......");
68 return;
69 }
70 }
71 // 如果不能通过
72 System.out.println("Sorry Server 不通过拦截器......");
73 // 抛出异常信息
74 throw new Fault(new RuntimeException("账号密码错误......"));
75 }
76
77 }
然后在服务器端的beans.xml进行配置,如下所示:
1 <?xml version="1.0" encoding="UTF-8"?>2 <beans xmlns="http://www.springframework.org/schema/beans"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xmlns:jaxws="http://cxf.apache.org/jaxws"5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd7 http://cxf.apache.org/jaxws http://cxf.apache.org/jaxws">8 9 <!-- 引cxf-2.5.9.jar此包下面的配置,这些配置不在此项目中,cxf的一些核心配置 -->
10 <import resource="classpath:META-INF/cxf/cxf.xml" />
11 <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
12 <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
13
14 <!--
15 jaxws:endpoint标签配置终端。
16 implementor是实现类。
17 address是虚拟地址。
18 -->
19 <jaxws:endpoint id="orderWS"
20 implementor="com.bie.webservice.ws.impl.OrderWSImpl"
21 address="/orderws">
22 <!-- 服务器端配置入拦截器 -->
23 <jaxws:inInterceptors>
24 <!-- 配置自定义的拦截器,注入到ioc容器中 -->
25 <bean class="com.bie.webservice.interceptor.CheckUserInterceptor"></bean>
26 </jaxws:inInterceptors>
27 </jaxws:endpoint>
28
29 </beans>
如果开发完毕,重启项目,报下面的错误,我的操作是clean项目,清空tomcat下面的项目,清空tomcat,重启项目解决的。
1 cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'context:property-placeholder' 的声明
第二步,Client端,通过Client对象设置出拦截器。
1 package com.bie.webservice.ws.interceptor;2 3 import java.util.List;4 5 import javax.xml.namespace.QName;6 import javax.xml.parsers.DocumentBuilder;7 import javax.xml.parsers.DocumentBuilderFactory;8 import javax.xml.parsers.ParserConfigurationException;9 10 import org.apache.cxf.binding.soap.SoapMessage;11 import org.apache.cxf.headers.Header;12 import org.apache.cxf.interceptor.Fault;13 import org.apache.cxf.phase.AbstractPhaseInterceptor;14 import org.apache.cxf.phase.Phase;15 import org.apache.xml.utils.DOMHelper;16 import org.w3c.dom.Document;17 import org.w3c.dom.Element;18 19 /**20 * 21 * @author 拦截的是某一个消息,所以泛型是SoapMessage22 *23 */24 public class ClientValidateUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {25 26 private String name;// 账号27 private String password;// 密码28 29 /**30 * 此构造器是关键点,决定了什么时候拦截器会拦截到消息31 * 32 * @param phase33 */34 public ClientValidateUserInterceptor(String name, String password) {35 // 准备协议化的时候进行拦截调用36 super(Phase.PRE_PROTOCOL);37 this.name = name;38 this.password = password;39 System.out.println("Client 客户端,拦截器初始化......");40 }41 42 /**43 * 请求体44 * 45 * <soap:Envelope> 46 * <head>47 * <zhangsansan>48 * <name>zhangsansan</name>49 * <password>123456</password>50 * </zhangsansan>51 * </head>52 * <Body> 53 * <sayHello> 54 * <arg0>张姗姗</arg0> 55 * </sayHello> 56 * </Body>57 * </soap:Envelope>58 */59 @Override60 public void handleMessage(SoapMessage soapMessage) throws Fault {61 // 获取到头信息,向头部信息设置值62 List<Header> headers = soapMessage.getHeaders();63 // 此时需要构造这种结构的数据64 // <zhangsansan>65 // <name>zhangsansan</name>66 // <password>123456</password>67 // </zhangsansan>68 69 // 第一步:初始化一个XML解析工厂70 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();71 // 第二步:创建一个DocumentBuilder实例72 DocumentBuilder builder = null;73 try {74 builder = factory.newDocumentBuilder();75 } catch (ParserConfigurationException e) {76 // TODO Auto-generated catch block77 e.printStackTrace();78 }79 // 第三步:构建一个Document实例80 Document doc = builder.newDocument();81 // standalone用来表示该文件是否呼叫其它外部的文件。若值是 ”yes” 表示没有呼叫外部文件82 doc.setXmlStandalone(true);83 // 第四步:创建一个根节点,名称为root,并设置一些基本属性,创建标签84 Element rootElement = doc.createElement("zhangsansan");85 // 设置节点属性86 // rootElement.setAttribute("attr", "root");87 // 设置标签之间的内容88 // rootElement.setTextContent("root attr");89 90 // 开始设置<zhangsansan>下面的标签<name>zhangsansan</name>91 Element nameElement = doc.createElement("name");92 nameElement.setTextContent(this.name);93 // 第五步:把节点添加到Document中,再创建一些子节点加入,将子标签添加到父标签中94 rootElement.appendChild(nameElement);95 96 // 开始设置<zhangsansan>下面的标签<name>zhangsansan</name>97 Element passwordElement = doc.createElement("password");98 passwordElement.setTextContent(this.password);99 // 第五步:把节点添加到Document中,再创建一些子节点加入,将子标签添加到父标签中
100 rootElement.appendChild(passwordElement);
101
102 // 第六步:把构造的XML结构,写入到具体的文件中
103 // 参数一QName起一个唯一的名字,这个名称必须和rootElement标签的值必须一样
104 // 参数二就是rootElement根节点
105 Header header = new Header(new QName("zhangsansan"), rootElement);
106 // 将此请求体和构建的请求头发送给服务器端
107 headers.add(header);
108
109 System.out.println("Client handleMessage Interceptor......");
110
111 // DOMHelper.createDocument()方法过期了
112 // Document createDocument = DOMHelper.createDocument();
113 }
114
115 }
然后在客户端的beans.xml进行配置,如下所示:
1 <?xml version="1.0" encoding="UTF-8"?>2 <beans xmlns="http://www.springframework.org/schema/beans"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xmlns:jaxws="http://cxf.apache.org/jaxws"5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd7 http://cxf.apache.org/jaxws http://cxf.apache.org/jaxws">8 9 <!--
10 客户端配置:
11 serviceClass根据此类动态产生接口的代理对象。
12 address是指的是webservice请求的地址。
13 -->
14 <jaxws:client id="orderClient"
15 serviceClass="com.bie.webservice.ws.OrderWS"
16 address="http://localhost:8080/webServiceCxf_Spring/orderws">
17
18 <!-- 客户端配置出拦截器类 -->
19 <jaxws:outInterceptors>
20 <!-- <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> -->
21 <bean
22 class="com.bie.webservice.ws.interceptor.ClientValidateUserInterceptor">
23 <!-- 通过构造参数传递给客户端拦截器类 -->
24 <constructor-arg name="name" value="张姗姗" />
25 <constructor-arg name="password" value="123456" />
26 </bean>
27 </jaxws:outInterceptors>
28 </jaxws:client>
29
30 </beans>
使用tomcat启动服务端,然后客户端访问服务端,效果如下所示: