zoukankan      html  css  js  c++  java
  • 【WebService】WebService之CXF的拦截器(五)

    CXF拦截器介绍

      CXF拦截器是功能的主要实现单元,也是主要的扩展点,可以在不对核心模块进行修改的情况下,动态添加功能。当服务被调用时,会经过多个拦截器链(Interceptor Chain)处理,拦截器链在服务输入(IN)或输出(OUT)阶段实现附加功能,拦截器可以在客户端加入,也可以在服务端加入。

      工作示意图如下:
        

      

      拦截器的拦截阶段:
        拦截器有多个阶段,每个阶段都有多个拦截器。拦截器在哪个阶段起作用,可以在拦截器的构造函数中声明。 

    输入拦截器有如下几个阶段,这些阶段按照在拦截器中的先后顺序排列。
    阶段名称阶段功能描述
    RECEIVE Transport level processing(接收阶段,传输层处理)
    (PRE/USER/POST)_STREAM Stream level processing/transformations(流处理/转换阶段)
    READ This is where header reading typically occurs(SOAPHeader读取)
    (PRE/USER/POST)_PROTOCOL Protocol processing, such as JAX-WS SOAP handlers(协议处理阶段,例如JAX-WS的Handler处理)
    UNMARSHAL Unmarshalling of the request(SOAP请求解码阶段)
    (PRE/USER/POST)_LOGICAL Processing of the umarshalled request(SOAP请求解码处理阶段)
    PRE_INVOKE Pre invocation actions(调用业务处理之前进入该阶段)
    INVOKE Invocation of the service(调用业务阶段)
    POST_INVOKE Invocation of the outgoing chain if there is one(提交业务处理结果,并触发输入连接器)

        

    输出拦截器有如下几个阶段,这些阶段按照在拦截器中的先后顺序排列。
    阶段名称阶段功能描述
    SETUP Any set up for the following phases(设置阶段)
    (PRE/USER/POST)_LOGICAL Processing of objects about to marshalled
    PREPARE_SEND Opening of the connection(消息发送准备阶段,在该阶段创建Connection)
    PRE_STREAM 流准备阶段
    PRE_PROTOCOL Misc protocol actions(协议准备阶段)
    WRITE Writing of the protocol message, such as the SOAP Envelope.(写消息阶段)
    MARSHAL Marshalling of the objects
    (USER/POST)_PROTOCOL Processing of the protocol message
    (USER/POST)_STREAM Processing of the byte level message(字节处理阶段,在该阶段把消息转为字节)
    SEND 消息发送

      

      


    在CXF中,所有对消息的处理都是通过各种拦截器实现。CXF已经实现了多种拦截器,如操纵消息头、执行认证检查、验证消息数据、日志记录、消息压缩等,有些拦截器在发布服务、访问服务时已经默认添加到拦截器。

    日志拦截器

      首先使用CXF搭建好WebService的客户端以及服务端。参照(【WebService】使用CXF开发WebService(四)),下例中使用的是上一篇的工程。

      1、服务器端的日志拦截器:主要是在发布的时候,添加输入和输出日志拦截器。代码如下:

     1 package com.test.ws.server;
     2 
     3 import java.util.List;
     4 
     5 import javax.xml.ws.Endpoint;
     6 
     7 import org.apache.cxf.interceptor.Interceptor;
     8 import org.apache.cxf.interceptor.LoggingInInterceptor;
     9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
    10 import org.apache.cxf.jaxws22.EndpointImpl;
    11 import org.apache.cxf.message.Message;
    12 
    13 import com.test.ws.HelloWSImpl;
    14 
    15 /**
    16  * 发布Web Service
    17  * @author H__D
    18  * @date 2017年7月28日 上午11:40:48
    19  *
    20  */
    21 public class ServerTest {
    22 
    23     public static void main(String[] args) {
    24         
    25         //定义WebService的发布地址,这个地址就是提供给外界访问Webervice的URL地址,URL地址格式为:http://ip:端口号/xxxx
    26         String address = "http://127.0.0.1:8989/test-webservice/hellows";
    27         //使用Endpoint类提供的publish方法发布WebService,发布时要保证使用的端口号没有被其他应用程序占用
    28         Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl());
    29         
    30         //打印endpoint,可以看到endpoint实际上是一个 org.apache.cxf.jaxws22.EndpointImpl 对象
    31         System.out.println("endpoint -->" + endpoint);
    32         
    33         //强转为EndpointImpl对象
    34         EndpointImpl endpointImpl = (EndpointImpl) endpoint;
    35         
    36         //服务端的日志入拦截器
    37         List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
    38         inInterceptors.add(new LoggingInInterceptor());
    39         
    40         //服务器端的日志出拦截器
    41         List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors();
    42         outInterceptors.add(new LoggingOutInterceptor());
    43         
    44         System.out.println("发布webservice成功!");
    45         
    46     }
    47 }

      

      2、客服端的日志拦截器:主要是在调整WebService的时候,添加输入和输出日志拦截器。(注:由于使用的是CXF拦截器,所以客户端也需要添加CXF相应的jar包)
        客户端添加CXF的jar包:
          
        调用代码如下:

     1 package com.test.ws.client;
     2 
     3 import java.util.List;
     4 
     5 import org.apache.cxf.endpoint.Client;
     6 import org.apache.cxf.frontend.ClientProxy;
     7 import org.apache.cxf.interceptor.Interceptor;
     8 import org.apache.cxf.interceptor.LoggingInInterceptor;
     9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
    10 import org.apache.cxf.message.Message;
    11 
    12 import com.test.ws.HelloWS;
    13 import com.test.ws.HelloWSImplService;
    14 
    15 /**
    16  * 调用WebService的客户端
    17  * @author H__D
    18  * @date 2017年7月28日 下午2:39:24
    19  *
    20  */
    21 public class WSClient {
    22 
    23     public static void main(String[] args) {
    24         //创建一个用于产生WebServiceImpl实例的工厂,WebServiceImplService类是wsimport工具生成的
    25         HelloWSImplService factory = new HelloWSImplService();
    26         //通过工厂生成一个WebServiceImpl实例,WebServiceImpl是wsimport工具生成的
    27         HelloWS helloWS = factory.getHelloWSImplPort();
    28         System.out.println(helloWS.getClass());
    29     
    30         //发送请求的客户端对象
    31         Client client = ClientProxy.getClient(helloWS);
    32         
    33         //客户端的日志入拦截器
    34         List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();
    35         inInterceptors.add(new LoggingInInterceptor());
    36         
    37         //客户端的日志出拦截器
    38         List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
    39         outInterceptors.add(new LoggingOutInterceptor());
    40         
    41         //调用WebService的sayHello方法
    42         String result = helloWS.sayHello("Jack");
    43         System.out.println(result);
    44     }
    45 
    46 }

      3、发布WebService服务端,然后使用客户端进行调用。控制台输出如下:
        服务端控制台输出:
          
        客户端控制台输出:
          

    自定义拦截器

      下面使用cxf自定义拦截器,客户端使用自定义拦截器添加用户信息,服务端使用自定义  拦截器获取用户信息并验证

      1、在服务端工程编写自定义拦截器,验证用户信息,代码如下

     1 package com.test.wx.interceptor;
     2 
     3 import java.util.List;
     4 
     5 import javax.xml.namespace.QName;
     6 
     7 import org.apache.cxf.binding.soap.SoapMessage;
     8 import org.apache.cxf.headers.Header;
     9 import org.apache.cxf.interceptor.Fault;
    10 import org.apache.cxf.phase.AbstractPhaseInterceptor;
    11 import org.apache.cxf.phase.Phase;
    12 import org.w3c.dom.Element;
    13 
    14 /**
    15  * 服务端权限拦截器
    16  * @author H__D
    17  * @date 2017年8月2日 下午2:22:02
    18  *
    19  */
    20 public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    21 
    22     public AuthInterceptor() {
    23         super(Phase.PRE_INVOKE); //拦截器在调用方法之前拦截SOAP消息  
    24     }
    25 
    26     /**
    27      * 拦截器操作
    28      * 信息如下
    29      * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    30      *         <soap:Header>
    31      *             <authHeader>
    32      *                 <name>hd</name>
    33      *                 <password>123456</password>
    34      *             </authHeader>
    35      *         </soap:Header>
    36      *         <soap:Body>
    37      *             <ns2:sayHello xmlns:ns2="http://ws.test.com/">
    38      *                 <arg0>Jack</arg0>
    39      *             </ns2:sayHello>
    40      *         </soap:Body>
    41      * </soap:Envelope>
    42      */
    43     @Override
    44     public void handleMessage(SoapMessage msg) throws Fault {
    45         System.out.println("com to auth interceptor...");
    46         
    47         //获取SOAP信息的所有Header
    48         List<Header> headers = msg.getHeaders();
    49         
    50         if(headers == null || headers.size() < 1)
    51         {
    52             throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截"));
    53         }
    54         
    55         boolean isAuth = false;
    56         //获取Header携带的用户名和密码信息
    57         for (Header header : headers) {
    58             //判断认证信息头
    59             if(new QName("authHeader").equals(header.getName()))
    60             {
    61                 //提取认证信息
    62                 Element element = (Element) header.getObject();
    63                 String name = element.getElementsByTagName("name").item(0).getTextContent();
    64                 String password = element.getElementsByTagName("password").item(0).getTextContent();
    65                 
    66                 if(name.equals("hd") && password.equals("123456"))
    67                 {
    68                     isAuth = true;
    69                     break;
    70                 }
    71             }
    72         }
    73         
    74         if(isAuth)
    75         {
    76             System.out.println("认证成功!!!");
    77         }else
    78         {
    79             throw new Fault(new IllegalArgumentException("用户名或密码不正确")); 
    80         }
    81     }
    82 
    83 }

        服务端设置好自定义拦截器,并进行发布,代码如下:

     1 package com.test.ws.server;
     2 
     3 import java.util.List;
     4 
     5 import javax.xml.ws.Endpoint;
     6 
     7 import org.apache.cxf.interceptor.Interceptor;
     8 import org.apache.cxf.interceptor.LoggingInInterceptor;
     9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
    10 import org.apache.cxf.jaxws22.EndpointImpl;
    11 import org.apache.cxf.message.Message;
    12 
    13 import com.test.ws.HelloWSImpl;
    14 import com.test.wx.interceptor.AuthInterceptor;
    15 
    16 /**
    17  * 发布Web Service
    18  * @author H__D
    19  * @date 2017年7月28日 上午11:40:48
    20  *
    21  */
    22 public class ServerTest {
    23 
    24     public static void main(String[] args) {
    25         
    26         //定义WebService的发布地址,这个地址就是提供给外界访问Webervice的URL地址,URL地址格式为:http://ip:端口号/xxxx
    27         String address = "http://127.0.0.1:8989/test-webservice/hellows";
    28         //使用Endpoint类提供的publish方法发布WebService,发布时要保证使用的端口号没有被其他应用程序占用
    29         Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl());
    30         
    31         //打印endpoint,可以看到endpoint实际上是一个 org.apache.cxf.jaxws22.EndpointImpl 对象
    32         System.out.println("endpoint -->" + endpoint);
    33         
    34         //强转为EndpointImpl对象
    35         EndpointImpl endpointImpl = (EndpointImpl) endpoint;
    36         
    37         //服务端的日志入拦截器
    38         List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
    39         inInterceptors.add(new LoggingInInterceptor());
    40         
    41         //服务端的自定义拦截器:验证用户名和密码
    42         inInterceptors.add(new AuthInterceptor());
    43         
    44         //服务器端的日志出拦截器
    45         List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors();
    46         outInterceptors.add(new LoggingOutInterceptor());
    47         
    48         System.out.println("发布webservice成功!");
    49         
    50     }
    51 }

      2、在客户端编写自定义拦截器,添加用户信息,代码如下:

     1 package com.test.interceptor;
     2 
     3 import java.util.List;
     4 
     5 import javax.xml.namespace.QName;
     6 
     7 import org.apache.cxf.binding.soap.SoapMessage;
     8 import org.apache.cxf.headers.Header;
     9 import org.apache.cxf.helpers.DOMUtils;
    10 import org.apache.cxf.interceptor.Fault;
    11 import org.apache.cxf.phase.AbstractPhaseInterceptor;
    12 import org.apache.cxf.phase.Phase;
    13 import org.w3c.dom.Document;
    14 import org.w3c.dom.Element;
    15 
    16 /**
    17  * 客户端添加用户信息拦截器
    18  * @author H__D
    19  * @date 2017年8月2日 下午2:47:08
    20  *
    21  */
    22 public class AddUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    23 
    24     private String name;
    25     private String password;
    26 
    27     public AddUserInterceptor(String name, String password) {
    28         
    29         super(Phase.PRE_PROTOCOL);//准备协议化时拦截
    30         this.name = name;
    31         this.password = password;
    32     }
    33 
    34     /**
    35      * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    36      *         <soap:Header>
    37      *             <authHeader>
    38      *                 <name>hd</name>
    39      *                 <password>123456</password>
    40      *             </authHeader>
    41      *         </soap:Header>
    42      *         <soap:Body>
    43      *             <ns2:sayHello xmlns:ns2="http://ws.test.com/">
    44      *                 <arg0>Jack</arg0>
    45      *             </ns2:sayHello>
    46      *         </soap:Body>
    47      * </soap:Envelope>
    48      */
    49     @Override
    50     public void handleMessage(SoapMessage msg) throws Fault {
    51         //获取消息头
    52         List<Header> headers = msg.getHeaders();
    53         
    54         //创建文档
    55         Document document = DOMUtils.createDocument();
    56         //创建根目录
    57         Element rootEle = document.createElement("authHeader");
    58         
    59         //配置head信息的用户名和密码
    60         Element nameEle = document.createElement("name");
    61         nameEle.setTextContent(name);
    62         Element passwordEle = document.createElement("password");
    63         passwordEle.setTextContent(password);
    64         
    65         rootEle.appendChild(nameEle);
    66         rootEle.appendChild(passwordEle);
    67         //将信息添加到头
    68         headers.add(new Header(new QName("authHeader"), rootEle));
    69     }
    70     
    71 }

        客户端添加自定义拦截器,并调用WebService服务,代码如下:

     1 package com.test.ws.client;
     2 
     3 import java.util.List;
     4 
     5 import org.apache.cxf.endpoint.Client;
     6 import org.apache.cxf.frontend.ClientProxy;
     7 import org.apache.cxf.interceptor.Interceptor;
     8 import org.apache.cxf.interceptor.LoggingInInterceptor;
     9 import org.apache.cxf.interceptor.LoggingOutInterceptor;
    10 import org.apache.cxf.message.Message;
    11 
    12 import com.test.interceptor.AddUserInterceptor;
    13 import com.test.ws.HelloWS;
    14 import com.test.ws.HelloWSImplService;
    15 
    16 /**
    17  * 调用WebService的客户端
    18  * @author H__D
    19  * @date 2017年7月28日 下午2:39:24
    20  *
    21  */
    22 public class WSClient {
    23 
    24     public static void main(String[] args) {
    25         //创建一个用于产生WebServiceImpl实例的工厂,WebServiceImplService类是wsimport工具生成的
    26         HelloWSImplService factory = new HelloWSImplService();
    27         //通过工厂生成一个WebServiceImpl实例,WebServiceImpl是wsimport工具生成的
    28         HelloWS helloWS = factory.getHelloWSImplPort();
    29         System.out.println(helloWS.getClass());
    30     
    31         //发送请求的客户端对象
    32         Client client = ClientProxy.getClient(helloWS);
    33         
    34         //客户端的日志入拦截器
    35         List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();
    36         inInterceptors.add(new LoggingInInterceptor());
    37         
    38         //客户端的日志出拦截器
    39         List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
    40         outInterceptors.add(new LoggingOutInterceptor());
    41         
    42         //添加自定义输出拦截器
    43         outInterceptors.add(new AddUserInterceptor("hd", "123456"));
    44         
    45         //调用WebService的sayHello方法
    46         String result = helloWS.sayHello("Jack");
    47         System.out.println(result);
    48     }
    49 
    50 }

      3、服务端控制台输出如下,可以看到自定义拦截器已经启用,并且获取到了用户名和密码进行验证。
          

      4、客户端控制台输出如下,可以看到自定义拦截器已经启用,并且添加了用户名和密码到消息的头里面。
          

      注:通过控制台可以看出,webservice服务器收到的是一段xml,而返回的也是xml,所有在调用webservcie的时候,可以使用ajax的post请求或者java里面HttpURLConnection来发送请求xml,然后获取响应xml进行处理。

  • 相关阅读:
    MFC tab页面中获到其它页面的数据
    sqlite数据库中"Select * From XXX能查到数据,但是Select DISTINCT group From xxx Order By group却查不出来
    关闭程序出现崩溃(exe 已触发了一个断点及未加载ucrtbased.pdb)
    springboot 通用Mapper使用
    springBoot 发布war包
    springCloud Zuul网关
    springboot hystrix turbine 聚合监控
    springBoot Feign Hystrix Dashboard
    springBoot Ribbon Hystrix Dashboard
    springBoot Feign Hystrix
  • 原文地址:https://www.cnblogs.com/h--d/p/7272621.html
Copyright © 2011-2022 走看看