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

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

 

2、CXF的拦截器分类:

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

 

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

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

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

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

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

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

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

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

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

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

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

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

 

4、CXF的拦截器API。

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

 

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

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

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

  1. 1 package com.bie.webservice.sei.interceptor;
  2. 2
  3. 3 import java.util.List;
  4. 4
  5. 5 import javax.xml.namespace.QName;
  6. 6 import javax.xml.parsers.DocumentBuilder;
  7. 7 import javax.xml.parsers.DocumentBuilderFactory;
  8. 8 import javax.xml.parsers.ParserConfigurationException;
  9. 9
  10. 10 import org.apache.cxf.binding.soap.SoapMessage;
  11. 11 import org.apache.cxf.headers.Header;
  12. 12 import org.apache.cxf.interceptor.Fault;
  13. 13 import org.apache.cxf.phase.AbstractPhaseInterceptor;
  14. 14 import org.apache.cxf.phase.Phase;
  15. 15 import org.apache.xml.utils.DOMHelper;
  16. 16 import org.w3c.dom.Document;
  17. 17 import org.w3c.dom.Element;
  18. 18
  19. 19 /**
  20. 20 *
  21. 21 * @author 拦截的是某一个消息,所以泛型是SoapMessage
  22. 22 *
  23. 23 */
  24. 24 public class ClientValidateUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
  25. 25
  26. 26 private String name;// 账号
  27. 27 private String password;// 密码
  28. 28
  29. 29 /**
  30. 30 * 此构造器是关键点,决定了什么时候拦截器会拦截到消息
  31. 31 *
  32. 32 * @param phase
  33. 33 */
  34. 34 public ClientValidateUserInterceptor(String name, String password) {
  35. 35 // 准备协议化的时候进行拦截调用
  36. 36 super(Phase.PRE_PROTOCOL);
  37. 37 this.name = name;
  38. 38 this.password = password;
  39. 39 }
  40. 40
  41. 41 /**
  42. 42 * 请求体
  43. 43 *
  44. 44 * <soap:Envelope>
  45. 45 * <head>
  46. 46 * <zhangsansan>
  47. 47 * <name>zhangsansan</name>
  48. 48 * <password>123456</password>
  49. 49 * </zhangsansan>
  50. 50 * </head>
  51. 51 * <Body>
  52. 52 * <sayHello>
  53. 53 * <arg0>张姗姗</arg0>
  54. 54 * </sayHello>
  55. 55 * </Body>
  56. 56 * </soap:Envelope>
  57. 57 */
  58. 58 @Override
  59. 59 public void handleMessage(SoapMessage soapMessage) throws Fault {
  60. 60 // 获取到头信息,向头部信息设置值
  61. 61 List<Header> headers = soapMessage.getHeaders();
  62. 62 // 此时需要构造这种结构的数据
  63. 63 // <zhangsansan>
  64. 64 // <name>zhangsansan</name>
  65. 65 // <password>123456</password>
  66. 66 // </zhangsansan>
  67. 67
  68. 68 // 第一步:初始化一个XML解析工厂
  69. 69 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  70. 70 // 第二步:创建一个DocumentBuilder实例
  71. 71 DocumentBuilder builder = null;
  72. 72 try {
  73. 73 builder = factory.newDocumentBuilder();
  74. 74 } catch (ParserConfigurationException e) {
  75. 75 // TODO Auto-generated catch block
  76. 76 e.printStackTrace();
  77. 77 }
  78. 78 // 第三步:构建一个Document实例
  79. 79 Document doc = builder.newDocument();
  80. 80 // standalone用来表示该文件是否呼叫其它外部的文件。若值是 ”yes” 表示没有呼叫外部文件
  81. 81 doc.setXmlStandalone(true);
  82. 82 // 第四步:创建一个根节点,名称为root,并设置一些基本属性,创建标签
  83. 83 Element rootElement = doc.createElement("zhangsansan");
  84. 84 // 设置节点属性
  85. 85 // rootElement.setAttribute("attr", "root");
  86. 86 // 设置标签之间的内容
  87. 87 // rootElement.setTextContent("root attr");
  88. 88
  89. 89 // 开始设置<zhangsansan>下面的标签<name>zhangsansan</name>
  90. 90 Element nameElement = doc.createElement("name");
  91. 91 nameElement.setTextContent(this.name);
  92. 92 // 第五步:把节点添加到Document中,再创建一些子节点加入,将子标签添加到父标签中
  93. 93 rootElement.appendChild(nameElement);
  94. 94
  95. 95 // 开始设置<zhangsansan>下面的标签<name>zhangsansan</name>
  96. 96 Element passwordElement = doc.createElement("password");
  97. 97 passwordElement.setTextContent(this.password);
  98. 98 // 第五步:把节点添加到Document中,再创建一些子节点加入,将子标签添加到父标签中
  99. 99 rootElement.appendChild(passwordElement);
  100. 100
  101. 101 // 第六步:把构造的XML结构,写入到具体的文件中
  102. 102 // 参数一QName起一个唯一的名字,这个名称必须和rootElement标签的值必须一样
  103. 103 // 参数二就是rootElement根节点
  104. 104 Header header = new Header(new QName("zhangsansan"), rootElement);
  105. 105 // 将此请求体和构建的请求头发送给服务器端
  106. 106 headers.add(header);
  107. 107
  108. 108 System.out.println("Client handleMessage Interceptor......");
  109. 109
  110. 110 // DOMHelper.createDocument()方法过期了
  111. 111 // Document createDocument = DOMHelper.createDocument();
  112. 112 }
  113. 113
  114. 114 }

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

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

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

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

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

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

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

 

版权声明:本文为biehongli原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/biehongli/p/14042662.html