• WebService入门学习二


    1、CXF框架的深入使用,CXF的拦截器,为什么设计CXF拦截器?

      答:为了在webservice请求过程中,能动态操作请求和响应数据,,CXF设计了拦截器。

    2、CXF的拦截器分类:

      1)、按所处的位置分:服务器端拦截器,客户端拦截器。
      2)、按消息的方向分:入拦截器,出拦截器。
      3)、按定义者分:系统拦截器,自定义拦截器。

    3、使用拦截器就可以不适用tcp/ip监控的工具了,因为此监控工具还需要将wsdl文件下载到本地,然后修改端口才能进行监控。

    将apache-cxf-2.5.9lib里面的包导入到项目中,然后编写SEI(Service Endpoint Interface),SEI在webservice中称为portType,在java中就是普通接口。

     1 package com.bie.webservice.sei;
     2 
     3 import javax.jws.WebMethod;
     4 import javax.jws.WebService;
     5 
     6 /**
     7  * 
     8  * @author
     9  *         编写SEI(Service Endpoint Interface),SEI在webservice中称为portType,在java中就是普通接口 。        
    10  * 
    11  *         1、第一步,开发服务器端,Web Service编码。
    12  *            –@WebService(SEI和SEI的实现类),该注解用来定义SEI和SEI的实现类。
    13  *         –@WebMethod(SEI中的所有方法),该注解用来定义SEI里面的方法。
    14  *         2、第二步,发布Web Service,–Endpoint(终端, 发布webservice)。
    15  */
    16 @WebService
    17 public interface HelloWebServiceSEI {
    18 
    19     @WebMethod
    20     public String sayHello(String name);
    21 
    22 }

    然后编写SEI实现类,如下所示:

     1 package com.bie.webservice.sei.impl;
     2 
     3 import javax.jws.WebService;
     4 
     5 import com.bie.webservice.sei.HelloWebServiceSEI;
     6 
     7 /**
     8  * 
     9  * @author
    10  * 
    11  *         1、SEI实现类
    12  *
    13  * 
    14  */
    15 @WebService // SEI实现类也要使用此注解
    16 public class HelloWebServiceSEIImpl implements HelloWebServiceSEI {
    17 
    18     @Override
    19     public String sayHello(String name) {
    20         System.out.println("Service server sayHello() : " + name);
    21         return "hello " + name;
    22     }
    23 
    24 }

    发布WebService,Endpoint(终端, 发布webservice),可以在服务器端编写拦截器,此拦截器可以替换掉tcp/ip监控工具。

     1 package com.bie.webservice.endpoint;
     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.bie.webservice.sei.HelloWebServiceSEI;
    14 import com.bie.webservice.sei.impl.HelloWebServiceSEIImpl;
    15 
    16 /**
    17  * 
    18  * @author 1、发布WebService,Endpoint(终端, 发布webservice)。
    19  *
    20  */
    21 public class WebServiceEndpoint {
    22 
    23     public static void main(String[] args) {
    24         // 使用Endpoint发布webservice
    25         // 参数一,url地址
    26         String address = "http://localhost:8888/webservice/hello";
    27         // 参数二,是SEI实现类对象
    28         HelloWebServiceSEI implementor = new HelloWebServiceSEIImpl();
    29         // 终端
    30         Endpoint endpoint = Endpoint.publish(address, implementor);
    31         System.out.println(endpoint.toString());
    32 
    33         // 将Endpoint转换为EndpointImpl,使用更多的实现方法
    34         EndpointImpl endpointImpl = (EndpointImpl) endpoint;
    35         // 如果要添加拦截器,是使用终端Endpoint来添加拦截器的,这里使用EndpointImpl来添加拦截器
    36         // 添加服务器端的入拦截器
    37         List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
    38         // 向拦截器集合中添加拦截器,添加服务器端的日志入拦截器
    39         inInterceptors.add(new LoggingInInterceptor());
    40 
    41         // 添加服务器端的日志出拦截器
    42         List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors();
    43         // 向拦截器集合中添加拦截器,添加服务器端的日志出拦截器
    44         outInterceptors.add(new LoggingOutInterceptor());
    45             
    46         System.out.println("使用Endpoint发布webservice,发布成功Success......");
    47     }
    48 
    49 }

    可以使用eclipse的web service浏览器进行测试,查看入拦截器和出拦截器的请求和相应参数是什么,如下所示:

    输入请求参数之后,就可以在控制台查看请求信息和响应信息,如下所示:

    同样,在客户端也可以进行入拦截器和出拦截器的配置,客户端的代码可以使用java的工具脚本wsimport自动生成的,这里省略了,同样,需要将apache-cxf-2.5.9lib里面的包导入到客户端项目中,如下所示:

     1 package com.bie.webservice.sei.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.bie.webservice.sei.HelloWebServiceSEI;
    13 import com.bie.webservice.sei.impl.HelloWebServiceSEIImplService;
    14 
    15 public class WebServiceCxfClient {
    16 
    17     public static void main(String[] args) {
    18         // 根据标签进行创建类<wsdl:service name="HelloWebServiceSEIImplService">
    19         HelloWebServiceSEIImplService factory = new HelloWebServiceSEIImplService();
    20         // 根据绑定的type为返回类型,<wsdl:binding name="HelloWebServiceSEIImplServiceSoapBinding"
    21         // type="ns1:HelloWebServiceSEI">
    22         HelloWebServiceSEI helloWebServiceSEI = factory.getHelloWebServiceSEIImplPort();
    23 
    24         // 服务器端使用的是终端EndPoint来进行添加拦截器的
    25         // 客户端是是使用的ClientProxy来获取到Client,Client即发送请求的客户端对象
    26         Client client = ClientProxy.getClient(helloWebServiceSEI);
    27         // 客户端的日志出拦截器
    28         List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
    29         // 向集合中添加出拦截器
    30         outInterceptors.add(new LoggingOutInterceptor());
    31 
    32         // 客户端的日志入拦截器
    33         List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();
    34         // 向集合中添加入拦截器
    35         inInterceptors.add(new LoggingInInterceptor());
    36 
    37         // 调用业务方法
    38         String sayHello = helloWebServiceSEI.sayHello("张姗姗");
    39         System.out.println("client : " + sayHello);
    40     }
    41 
    42 }

    客户端请求,入拦截器和出拦截器,已经请求方法返回信息打印的结果,如下所示:

    4、CXF的拦截器API。

      1)、Interceptor(拦截器接口)。
      2)、AbstractPhaseInterceptor(自定义拦截器从此继承)。
      3)、LoggingInInterceptor(系统日志入拦截器类)。使用日志拦截器,可以实现日志记录,日志拦截器有LoggingInInterceptor,LoggingOutInterceptor。
      4)、LoggingOutInterceptor(系统日志出拦截器类)。使用日志拦截器,可以实现日志记录,日志拦截器有LoggingInInterceptor,LoggingOutInterceptor。

    5、使用自定义拦截器,实现用户名与密码的检验,对于客户端的出拦截器,入拦截器,服务器端的入拦截器,出拦截器如何进行添加拦截器进行账号密码校验呢?

      答:需要在服务器端的in拦截器,客户端的out拦截器添加拦截器进行校验。

    首先搞一个客户端的出拦截器,进行拦截,如下所示:

      1 package com.bie.webservice.sei.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     }
     40 
     41     /**
     42      * 请求体
     43      * 
     44      * <soap:Envelope> 
     45      *     <head>
     46      *         <zhangsansan>
     47      *             <name>zhangsansan</name>
     48      *             <password>123456</password>
     49      *         </zhangsansan>
     50      *  </head>
     51      *     <Body> 
     52      *         <sayHello> 
     53      *             <arg0>张姗姗</arg0> 
     54      *         </sayHello> 
     55      *     </Body>
     56      * </soap:Envelope>
     57      */
     58     @Override
     59     public void handleMessage(SoapMessage soapMessage) throws Fault {
     60         // 获取到头信息,向头部信息设置值
     61         List<Header> headers = soapMessage.getHeaders();
     62         // 此时需要构造这种结构的数据
     63 //        <zhangsansan>
     64 //            <name>zhangsansan</name>
     65 //            <password>123456</password>
     66 //        </zhangsansan>
     67         
     68         // 第一步:初始化一个XML解析工厂
     69         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
     70         // 第二步:创建一个DocumentBuilder实例
     71         DocumentBuilder builder = null;
     72         try {
     73             builder = factory.newDocumentBuilder();
     74         } catch (ParserConfigurationException e) {
     75             // TODO Auto-generated catch block
     76             e.printStackTrace();
     77         }
     78         // 第三步:构建一个Document实例
     79         Document doc = builder.newDocument();
     80         // standalone用来表示该文件是否呼叫其它外部的文件。若值是 ”yes” 表示没有呼叫外部文件
     81         doc.setXmlStandalone(true);
     82         // 第四步:创建一个根节点,名称为root,并设置一些基本属性,创建标签
     83         Element rootElement = doc.createElement("zhangsansan");
     84         // 设置节点属性
     85         // rootElement.setAttribute("attr", "root");
     86         // 设置标签之间的内容
     87         // rootElement.setTextContent("root attr");
     88         
     89         // 开始设置<zhangsansan>下面的标签<name>zhangsansan</name>
     90         Element nameElement = doc.createElement("name");
     91         nameElement.setTextContent(this.name);
     92         // 第五步:把节点添加到Document中,再创建一些子节点加入,将子标签添加到父标签中
     93         rootElement.appendChild(nameElement);
     94         
     95         // 开始设置<zhangsansan>下面的标签<name>zhangsansan</name>
     96         Element passwordElement = doc.createElement("password");
     97         passwordElement.setTextContent(this.password);
     98         // 第五步:把节点添加到Document中,再创建一些子节点加入,将子标签添加到父标签中
     99         rootElement.appendChild(passwordElement);
    100         
    101         // 第六步:把构造的XML结构,写入到具体的文件中
    102         // 参数一QName起一个唯一的名字,这个名称必须和rootElement标签的值必须一样
    103         // 参数二就是rootElement根节点
    104         Header header = new Header(new QName("zhangsansan"), rootElement);
    105         // 将此请求体和构建的请求头发送给服务器端
    106         headers.add(header);
    107         
    108         System.out.println("Client handleMessage Interceptor......");
    109         
    110         // DOMHelper.createDocument()方法过期了
    111         // Document createDocument = DOMHelper.createDocument();
    112     }
    113 
    114 }

    然后在客户端新增自定义的出拦截器,验证账号密码信息,如下所示:

     1 package com.bie.webservice.sei.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.message.Message;
     9 
    10 import com.bie.webservice.sei.HelloWebServiceSEI;
    11 import com.bie.webservice.sei.impl.HelloWebServiceSEIImplService;
    12 import com.bie.webservice.sei.interceptor.ClientValidateUserInterceptor;
    13 
    14 public class WebServiceCxfClient2 {
    15 
    16     public static void main(String[] args) {
    17         // 根据标签进行创建类<wsdl:service name="HelloWebServiceSEIImplService">
    18         HelloWebServiceSEIImplService factory = new HelloWebServiceSEIImplService();
    19         // 根据绑定的type为返回类型,<wsdl:binding name="HelloWebServiceSEIImplServiceSoapBinding"
    20         // type="ns1:HelloWebServiceSEI">
    21         HelloWebServiceSEI helloWebServiceSEI = factory.getHelloWebServiceSEIImplPort();
    22 
    23         // 服务器端使用的是终端EndPoint来进行添加拦截器的
    24         // 客户端是是使用的ClientProxy来获取到Client,Client即发送请求的客户端对象
    25         Client client = ClientProxy.getClient(helloWebServiceSEI);
    26         // 账号密码的校验,要使用的是客户端的出拦截器
    27         List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
    28         // 向集合中添加自定义的出拦截器
    29         String name = "张姗姗";
    30         String password = "123456";
    31         outInterceptors.add(new ClientValidateUserInterceptor(name, password));
    32 
    33         // 调用业务方法
    34         String sayHello = helloWebServiceSEI.sayHello("张姗姗");
    35         System.out.println("client : " + sayHello);
    36     }
    37 
    38 }

    然后搞一个服务器端的入拦截器,验证账号密码是否正常,如下所示:

     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  * @author 服务器端的自定义入拦截器
    16  *
    17  */
    18 public class ServerValidateUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    19 
    20     private static final String name = "张姗姗";
    21     private static final String password = "123456";
    22     
    23     public ServerValidateUserInterceptor() {
    24         // 准备协议化的时候进行拦截调用
    25         super(Phase.PRE_PROTOCOL);
    26     }
    27 
    28     /**
    29      * 请求体,服务器端需要解析请求头信息
    30      * 
    31      * <soap:Envelope> 
    32      *     <head>
    33      *         <zhangsansan>
    34      *             <name>zhangsansan</name>
    35      *             <password>123456</password>
    36      *         </zhangsansan>
    37      *  </head>
    38      *     <Body> 
    39      *         <sayHello> 
    40      *             <arg0>张姗姗</arg0> 
    41      *         </sayHello> 
    42      *     </Body>
    43      * </soap:Envelope>
    44      */
    45     @Override
    46     public void handleMessage(SoapMessage soapMessage) throws Fault {
    47         // 获取到请求头的信息
    48         QName qName = QName.valueOf("zhangsansan");
    49         // 获取到请求头
    50         Header header = soapMessage.getHeader(qName);
    51         // 判断是否为空
    52         if(header != null) {
    53             // 获取到对象,强转为w3c的元素标签
    54             Element element = (Element) header.getObject();
    55             // 获取到name标签的值
    56             Node nameNode = element.getElementsByTagName("name").item(0);
    57             // 获取到name的值
    58             String nameValue = nameNode.getTextContent();
    59             // 获取到pasword标签的值
    60             Node passwordNode = element.getElementsByTagName("password").item(0);
    61             // 获取到pasword的值
    62             String paswordValue = passwordNode.getTextContent();
    63             // 开始进行判断
    64             if(ServerValidateUserInterceptor.name.equals(nameValue) && ServerValidateUserInterceptor.password.equals(paswordValue)) {
    65                 System.out.println("Server 通过拦截器......");
    66                 return;
    67             }
    68         }
    69         // 如果不能通过
    70         System.out.println("Sorry Server 不通过拦截器......");
    71         // 抛出异常信息
    72         throw new Fault(new RuntimeException("账号密码错误......"));
    73     }
    74 
    75 }

    然后在服务器端添加自定义的入拦截器,如下所示:

     1 package com.bie.webservice.endpoint;
     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.jaxws22.EndpointImpl;
     9 import org.apache.cxf.message.Message;
    10 
    11 import com.bie.webservice.interceptor.ServerValidateUserInterceptor;
    12 import com.bie.webservice.sei.HelloWebServiceSEI;
    13 import com.bie.webservice.sei.impl.HelloWebServiceSEIImpl;
    14 
    15 /**
    16  * 
    17  * @author 1、发布WebService,Endpoint(终端, 发布webservice)。
    18  *
    19  */
    20 public class WebServiceEndpoint2 {
    21 
    22     public static void main(String[] args) {
    23         // 使用Endpoint发布webservice
    24         // 参数一,url地址
    25         String address = "http://localhost:8888/webservice/hello";
    26         // 参数二,是SEI实现类对象
    27         HelloWebServiceSEI implementor = new HelloWebServiceSEIImpl();
    28         // 终端
    29         Endpoint endpoint = Endpoint.publish(address, implementor);
    30         System.out.println(endpoint.toString());
    31 
    32         // 将Endpoint转换为EndpointImpl,使用更多的实现方法
    33         EndpointImpl endpointImpl = (EndpointImpl) endpoint;
    34         // 如果要添加拦截器,是使用终端Endpoint来添加拦截器的,这里使用EndpointImpl来添加拦截器
    35         // 添加服务器端的入拦截器
    36         List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
    37         // 向拦截器集合中添加拦截器,添加服务器端的账号密码验证的入拦截器
    38         inInterceptors.add(new ServerValidateUserInterceptor());
    39 
    40         System.out.println("使用Endpoint发布webservice,发布成功Success......");
    41     }
    42 
    43 }

    启动服务器端服务,然后启动客户端服务,分别输入正确的账号密码,和错误的账号密码进行验证。

  • 相关阅读:
    LeetCode
    已知二叉树的先序遍历和中序遍历序列求后序遍历序列
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    TCP协议的基本规则和在Java中的使用
    Java中UDP协议的基本原理和简单用法
    LeetCode
  • 原文地址:https://www.cnblogs.com/biehongli/p/14042662.html
Copyright © 2020-2023  润新知