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进行处理。

  • 相关阅读:
    docker
    SAML(Security assertion markUp language) 安全断言标记语言
    kafka消息系统
    OBS 对象存储技术学习
    AOP之AspectJ
    sql查漏补缺
    todolist
    springboot 注解整理
    前端之jQuery
    前端之BOM和DOM
  • 原文地址:https://www.cnblogs.com/h--d/p/7272621.html
Copyright © 2011-2022 走看看