6、Web Service-拦截器
1、为什么CXF设置拦截器
为了在webservice请求过程中,能动态操作请求和响应数据, CXF设计了拦截器。拦截器分类
1.按所处的位置分:服务器端拦截器,客户端拦截器
2.按消息的方向分:入拦截器,出拦截器
3.按定义者分:系统拦截器,自定义拦截器
系统拦截器:
LoggingInInterceptor(系统日志入拦截器类)
LoggingOutInterceptor(系统日志出拦截器类)
2、系统拦截器
https://www.cnblogs.com/Mrchengs/p/10562458.html依旧是这里的服务端代码进行使用
1、服务端的拦截
在发布的main方法中:
package com.cr.server; import java.util.List; import javax.wsdl.Message; import javax.xml.ws.Endpoint; import org.apache.cxf.interceptor.Interceptor;import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.EndpointImpl; import com.cr.service.impl.HelloServiceImpl; import service1.DateTypeWsImpl; //发布service public class server { public static void main(String[] args){ String address = "http://localhost:8081/webserviceserver/helloService"; Endpoint endpoint = Endpoint.publish(address , new HelloServiceImpl()); System.out.println(endpoint); EndpointImpl e = (EndpointImpl) endpoint; System.out.println(e); //服务端的日志入拦截器 List<Interceptor<? extends org.apache.cxf.message.Message>> in = e.getInInterceptors(); in.add(new LoggingInInterceptor()); List<Interceptor<? extends org.apache.cxf.message.Message>> out = e.getOutInterceptors(); out.add(new LoggingOutInterceptor()); System.out.println(); System.out.println("发布成功...."); } }
测试结果:
---------------------------- ID: 1 Address: http://localhost:8081/webserviceserver/helloService?wsdl Http-Method: GET Content-Type: Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[localhost:8081], User-Agent=[Java/1.8.0_101]} -------------------------------------- 三月 21, 2019 9:33:01 下午 org.apache.cxf.services.HelloServiceImplService.HelloServiceImplPort.HelloService 信息: Inbound Message ---------------------------- ID: 2 Address: http://localhost:8081/webserviceserver/helloService?wsdl Http-Method: GET Content-Type: Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[localhost:8081], User-Agent=[Java/1.8.0_101]} -------------------------------------- 三月 21, 2019 9:33:01 下午 org.apache.cxf.services.HelloServiceImplService.HelloServiceImplPort.HelloService 信息: Inbound Message ---------------------------- ID: 3 Address: http://localhost:8081/webserviceserver/helloService?wsdl=HelloService.wsdl Http-Method: GET Content-Type: Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[localhost:8081], User-Agent=[Java/1.8.0_101]} -------------------------------------- 三月 21, 2019 9:33:02 下午 org.apache.cxf.services.HelloServiceImplService.HelloServiceImplPort.HelloService 信息: Inbound Message ---------------------------- ID: 4 Address: http://localhost:8081/webserviceserver/helloService?wsdl=HelloService.wsdl Http-Method: GET Content-Type: Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[localhost:8081], User-Agent=[Java/1.8.0_101]} -------------------------------------- 三月 21, 2019 9:33:02 下午 org.apache.cxf.services.HelloServiceImplService.HelloServiceImplPort.HelloService 信息: Inbound Message ---------------------------- ID: 5 Address: http://localhost:8081/webserviceserver/helloService?wsdl=HelloService.wsdl Http-Method: GET Content-Type: Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[localhost:8081], User-Agent=[Java/1.8.0_101]} -------------------------------------- 三月 21, 2019 9:33:11 下午 org.apache.cxf.services.HelloServiceImplService.HelloServiceImplPort.HelloService 信息: Inbound Message ---------------------------- ID: 6 Address: http://localhost:8081/webserviceserver/helloService Encoding: UTF-8 Http-Method: POST Content-Type: text/xml; charset=UTF-8 Headers: {Accept=[application/soap+xml, application/dime, multipart/related, text/*], Cache-Control=[no-cache], connection=[close], Content-Length=[330], content-type=[text/xml; charset=UTF-8], Host=[localhost:8081], Pragma=[no-cache], SOAPAction=[""], User-Agent=[IBM Web Services Explorer]} Payload: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://service.cr.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <q0:sayHello> <arg0>1</arg0> </q0:sayHello> </soapenv:Body> </soapenv:Envelope> -------------------------------------- webservice sercer... name:1 三月 21, 2019 9:33:11 下午 org.apache.cxf.services.HelloServiceImplService.HelloServiceImplPort.HelloService 信息: Outbound Message --------------------------- ID: 6 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml Headers: {} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHelloResponse xmlns:ns2="http://service.cr.com/"><return>hello:1</return></ns2:sayHelloResponse></soap:Body></soap:Envelope> --------------------------------------
2、客户端的拦截
package cn.com.client; import java.util.List; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.interceptor.Interceptor; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.message.Message; import com.cr.service.HelloService; import com.cr.service.impl.HelloServiceImplService; public class client { public static void main(String[] args){ HelloServiceImplService factory = new HelloServiceImplService(); HelloService hello = factory.getHelloServiceImplPort(); //发送请求的客户端对象 Client client = ClientProxy.getClient(hello); //添加日志出拦截器的集合 List<Interceptor<? extends Message>> out = client.getOutInterceptors(); out.add(new LoggingOutInterceptor()); //添加日志出拦截器的集合 List<Interceptor<? extends Message>> in = client.getInInterceptors(); in.add(new LoggingInInterceptor()); String res = hello.sayHello("mr"); System.out.println("end:"+res); } }
--------------------------- ID: 1 Address: http://localhost:8081/webserviceserver/helloService Encoding: UTF-8 Http-Method: POST Content-Type: text/xml Headers: {Accept=[*/*], SOAPAction=[""]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHello xmlns:ns2="http://service.cr.com/"><arg0>mr</arg0></ns2:sayHello></soap:Body></soap:Envelope> -------------------------------------- 三月 21, 2019 9:59:28 下午 org.apache.cxf.services.HelloServiceImplService.HelloServiceImplPort.HelloService 信息: Inbound Message ---------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml;charset=utf-8 Headers: {content-type=[text/xml;charset=utf-8], Date=[Thu, 21 Mar 2019 13:59:28 GMT], Server=[Jetty(9.4.14.v20181114)], transfer-encoding=[chunked]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHelloResponse xmlns:ns2="http://service.cr.com/"><return>hello:mr</return></ns2:sayHelloResponse></soap:Body></soap:Envelope> -------------------------------------- end:hello:mr
首先是从客户端发送请求给服务器,先是发出请求给服务器被拦截(客户端出拦截器),服务器返回响应数据后又被客户端拦截器拦截(客户端入拦截器)
服务器接收到客户端请求后,该请求先是被拦截(服务器入拦截器),接着服务器接收请求并执行后,将数据发回给客户端又被拦截(服务器出拦截器)
3、自定义拦截器
案例:使用自定义拦截器,实现用户名和密码的权限,即访问权限控制!
需要的拦截器:客户端的出拦截器和服务器的入拦截器
说明:自定义拦截器都从AbstractPhaseIntercepter继承
问题:为什么客户端需要设置拦截器?
因为客户端拦截器能得到客户端的用户名和密码,并且将用户名和密码设置到请求头中
这样服务器接收请求时才能获取到用户名和密码,并且根据得到的用户名和密码来做出验证!
关于客户端的拦截器设置:
新建拦截类:
AddUserInterceptor.java
package com.interceptor; import java.util.List; import javax.xml.namespace.QName; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.headers.Header; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.sun.org.apache.xml.internal.utils.DOMHelper; import com.sun.xml.internal.ws.message.DOMHeader; public class AddUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> { private String name; private String pwd; //Phase.class可以查看相关的值 public AddUserInterceptor(String name,String pwd) { super(Phase.PRE_PROTOCOL);//准备初始化拦截 this.name=name; this.pwd=pwd; } /* <Envelope> <head> <cr> <name>name</name> <pwd>pwd</pwd> </cr> </head> <body> //... </body> </Envelope> */ @Override public void handleMessage(SoapMessage msg) throws Fault { List<Header> header = msg.getHeaders(); /* <head> <cr> <name>name</name> <pwd>pwd</pwd> </cr> </hean> */ Document document = DOMHelper.createDocument(); Element cr = document.createElement("cr");//创建标签<cr></cr> Element name = document.createElement("name");//创建标签<name></name> name.setTextContent(this.name); cr.appendChild(name);//将name加入到cr标签中
Element pwd = document.createElement("pwd"); pwd.setTextContent(this.pwd); cr.appendChild(pwd);
//设置《cr》标签的cr header.add(new Header(new QName("cr"), cr)); System.out.println("clinet....."); } }
在客户端的使用
package cn.com.client; import java.util.List; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.interceptor.Interceptor; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.message.Message; import com.cr.service.HelloService; import com.cr.service.impl.HelloServiceImplService; import com.interceptor.AddUserInterceptor; public class client3 { public static void main(String[] args){ HelloServiceImplService factory = new HelloServiceImplService(); HelloService hello = factory.getHelloServiceImplPort(); //发送请求的客户端对象 Client client = ClientProxy.getClient(hello); //添加日志出拦截器的集合 List<Interceptor<? extends Message>> out = client.getOutInterceptors(); out.add(new AddUserInterceptor("cr", "123")); String res = hello.sayHello("mr"); System.out.println("end:"+res); } }
关于服务器端的拦截类:
package interceptor; import javax.xml.namespace.QName; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.headers.Header; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.w3c.dom.Element; public class CheckUserInterceptor extends AbstractPhaseInterceptor<SoapMessage>{ public CheckUserInterceptor() { super(Phase.PRE_PROTOCOL);//准备初始化拦截 } @Override public void handleMessage(SoapMessage msg) throws Fault { Header header = msg.getHeader(new QName("cr")); if(header!=null){ //取出数据 Element e =(Element) header.getObject();
//取出name标签的值 String name = e.getElementsByTagName("name").item(0).getTextContent();
//取出pwd标签的值 String pwd = e.getElementsByTagName("pwd").item(0).getTextContent();
if("cr".equals(name) && "123".equals(pwd)){ System.out.println("用户密码正确..."); return; } //没有通过 System.out.println("不正确..."); throw new Fault(new RuntimeException("请求需要正确的账户....")); } } }
发布类中:
package com.cr.server; import java.util.List; import javax.wsdl.Message; import javax.xml.ws.Endpoint; import org.apache.cxf.interceptor.Interceptor;import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.EndpointImpl; import com.cr.service.impl.HelloServiceImpl; import interceptor.CheckUserInterceptor; import service1.DateTypeWsImpl; //发布service public class server2 { public static void main(String[] args){ String address = "http://localhost:8081/webserviceserver/helloService"; Endpoint endpoint = Endpoint.publish(address , new HelloServiceImpl()); System.out.println(endpoint); EndpointImpl e = (EndpointImpl) endpoint; System.out.println(e); //服务端的日志入拦截器 List<Interceptor<? extends org.apache.cxf.message.Message>> in = e.getInInterceptors(); in.add(new CheckUserInterceptor()); System.out.println("发布成功...."); } }
测试:正确的情况下:
客户端的打印:
三月 21, 2019 10:58:49 下午 org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL 信息: Creating Service {http://impl.service.cr.com/}HelloServiceImplService from WSDL: file:/D:/myeclipse/MyEclipseProject/webservices_cxf_client/client.wsdl clinet..... end:hello:mr
服务端的打印;
用户密码正确...
webservice sercer...
name:mr
测试:错误的i情况下:
客户端的打印:
三月 21, 2019 10:59:55 下午 org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL 信息: Creating Service {http://impl.service.cr.com/}HelloServiceImplService from WSDL: file:/D:/myeclipse/MyEclipseProject/webservices_cxf_client/client.wsdl clinet..... Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: 请求需要正确的账户.... at org.apache.cxf.jaxws.JaxWsClientProxy.mapException(JaxWsClientProxy.java:195) at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:145) at com.sun.proxy.$Proxy35.sayHello(Unknown Source) at cn.com.client.client3.main(client3.java:29) Caused by: org.apache.cxf.binding.soap.SoapFault: 请求需要正确的账户....
服务端的打印:
不正确... 三月 21, 2019 10:59:55 下午 org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging 警告: Interceptor for {http://impl.service.cr.com/}HelloServiceImplService has thrown exception, unwinding now org.apache.cxf.interceptor.Fault: 请求需要正确的账户.... at interceptor.CheckUserInterceptor.handleMessage(CheckUserInterceptor.java:33) at interceptor.CheckUserInterceptor.handleMessage(CheckUserInterceptor.java:1) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:267) at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:247) at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:79)
.....