• 基于Spring + CXF框架的Web Service


    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.9lib目录下面的包添加到此动态工程的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  * @author
     6  *
     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.xsd
     7         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.9lib目录下面的包添加到此动态工程的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.xsd
     7     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.xsd
     7         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 拦截的是某一个消息,所以泛型是SoapMessage
     22  *
     23  */
     24 public class ClientValidateUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
     25 
     26     private String name;// 账号
     27     private String password;// 密码
     28 
     29     /**
     30      * 此构造器是关键点,决定了什么时候拦截器会拦截到消息
     31      * 
     32      * @param phase
     33      */
     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     @Override
     60     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 block
     77             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.xsd
     7     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启动服务端,然后客户端访问服务端,效果如下所示:

  • 相关阅读:
    原来针对新唐mcu,keil有免费许可
    使用IAR在开发nordic问题记录
    arm的开发工具
    nordic芯片开发——烧写方法记录
    生活感想(三)——心理学其实很有用
    生活感想(二)——心理学其实很有用
    多线程编程基础知识
    多线程编程简介
    winsock的io模型(终极篇)
    ioctlsocket()函数是干什么用的?它返回值是什么?共有几个参数?它的各个参数是干什么用的?
  • 原文地址:https://www.cnblogs.com/biehongli/p/14044009.html
Copyright © 2020-2023  润新知