CXF为什么要设计拦截器?
为了在webservice请求过程中,能动态操作请求和响应数据, CXF设计了拦截器。
拦截器分类
1.按所处的位置分:服务器端拦截器,客户端拦截器
2.按消息的方向分:入拦截器,出拦截器
3.按定义者分:系统拦截器,自定义拦截器
3.1系统拦截器:
LoggingInInterceptor(系统日志入拦截器类)
LoggingOutInterceptor(系统日志出拦截器类)
***server*** //SEI @WebService public interface HelloWS { @WebMethod public String sayHello(String name); } //SEI implement @WebService public class HelloWSImpl implements HelloWS { @Override public String sayHello(String name) { return "hello: "+name; } } //publish public class RealeaseWS { public static void main(String[] args) { String address = "http://localhost:8989/WebService_Server"; Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl()); EndpointImpl endpointImpl = (EndpointImpl)endpoint; //服务器的的入拦截器 List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors(); //将系统日志入拦截器类添加到入拦截器集合中 inInterceptors.add(new LoggingInInterceptor()); //服务器的的出拦截器 List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors(); //将系统日志出拦截器类添加到出拦截器集合中 outInterceptors.add(new LoggingOutInterceptor()); System.out.println("webService发布成功!"); } }
***client*** //生成客户端代码步骤省略。。。 //客户端调用服务器方法测试程序 public class TestWebService { public static void main(String[] args) { HelloWSImplService factory = new HelloWSImplService(); HelloWSImpl helloWSImpl = factory.getHelloWSImplPort(); //在调用服务器方法前配置拦截器 //获取发送请求的客户端对象 Client client = ClientProxy.getClient(helloWSImpl); //客户端的系统日志出拦截器 List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors(); outInterceptors.add(new LoggingOutInterceptor()); //客户端的系统日志入拦截器 List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors(); inInterceptors.add(new LoggingInInterceptor()); String result = helloWSImpl.sayHello("webService"); System.out.println(result); } }
执行程序后日志:
1.首先是从客户端发送请求给服务器,先是发出请求给服务器被拦截(客户端出拦截器),服务器返回响应数据后又被客户端拦截器拦截(客户端入拦截器),拦截信息如下: 一月 26, 2016 10:32:44 下午 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL INFO: Creating Service {http://server.webService.com/}HelloWSImplService from WSDL: http://localhost:8989/WebService_Server?wsdl 一月 26, 2016 10:32:45 下午 org.apache.cxf.services.HelloWSImplService.HelloWSImplPort.HelloWS INFO: Outbound Message --------------------------- ID: 1 Address: http://localhost:8989/WebService_Server Encoding: UTF-8 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://server.webService.com/"><arg0>webService</arg0></ns2:sayHello></soap:Body></soap:Envelope> -------------------------------------- 一月 26, 2016 10:32:45 下午 org.apache.cxf.services.HelloWSImplService.HelloWSImplPort.HelloWS INFO: Inbound Message ---------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml;charset=UTF-8 Headers: {Content-Length=[230], content-type=[text/xml;charset=UTF-8], Server=[Jetty(7.5.4.v20111024)]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHelloResponse xmlns:ns2="http://server.webService.com/"><return>hello: webService</return></ns2:sayHelloResponse></soap:Body></soap:Envelope> -------------------------------------- hello: webService
2.服务器接收到客户端请求后,该请求先是被拦截(服务器入拦截器),接着服务器接收请求并执行后,将数据发回给客户端又被拦截(服务器出拦截器),该拦截信息为: 一月 26, 2016 10:20:35 下午 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass INFO: Creating Service {http://server.webService.com/}HelloWSImplService from class com.webService.server.HelloWS 一月 26, 2016 10:20:38 下午 org.apache.cxf.endpoint.ServerImpl initDestination INFO: Setting the server's publish address to be http://localhost:8989/WebService_Server 一月 26, 2016 10:20:38 下午 org.eclipse.jetty.server.Server doStart INFO: jetty-7.5.4.v20111024 一月 26, 2016 10:20:38 下午 org.eclipse.jetty.server.AbstractConnector doStart INFO: Started SelectChannelConnector@localhost:8989 STARTING 一月 26, 2016 10:20:38 下午 org.eclipse.jetty.server.handler.ContextHandler startContext INFO: started o.e.j.s.h.ContextHandler{,null} webService发布成功! 一月 26, 2016 10:32:44 下午 org.apache.cxf.services.HelloWSImplService.HelloWSImplPort.HelloWS INFO: Inbound Message ---------------------------- ID: 1 Address: http://localhost:8989/WebService_Server?wsdl Encoding: UTF-8 Http-Method: GET Content-Type: text/xml Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], content-type=[text/xml], Host=[localhost:8989], Pragma=[no-cache], User-Agent=[Apache CXF 2.5.9]} -------------------------------------- 一月 26, 2016 10:32:45 下午 org.apache.cxf.services.HelloWSImplService.HelloWSImplPort.HelloWS INFO: Inbound Message ---------------------------- ID: 2 Address: http://localhost:8989/WebService_Server Encoding: UTF-8 Http-Method: POST Content-Type: text/xml; charset=UTF-8 Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[203], content-type=[text/xml; charset=UTF-8], Host=[localhost:8989], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 2.5.9]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHello xmlns:ns2="http://server.webService.com/"><arg0>webService</arg0></ns2:sayHello></soap:Body></soap:Envelope> --------------------------------------
3.2自定义拦截器
案例:使用自定义拦截器,实现用户名和密码的权限,即访问权限控制!
需要的拦截器:客户端的出拦截器和服务器的入拦截器
说明:自定义拦截器都从AbstractPhaseIntercepter继承
问题:为什么客户端需要设置拦截器?
因为客户端拦截器能得到客户端的用户名和密码,并且将用户名和密码设置到请求头中,这样服务器接收请求时才能获取到用户名和密码,并且根据得到的用户名和密码来做出验证!
***客户端拦截器*** public class AccountInterceptor extends AbstractPhaseInterceptor<SoapMessage>{ private String name; private String password; public AccountInterceptor(String name,String password) { //Phase值决定了拦截器什么时候拦截到消息 //PRE_PROTOCOL准备请求时拦截 super(Phase.PRE_PROTOCOL); this.name = name; this.password = password; } //一旦被拦截,首先调用此方法 @SuppressWarnings("deprecation") @Override public void handleMessage(SoapMessage msg) throws Fault { List<Header> headers = msg.getHeaders(); //在客户端请求时,会将用户名密码带过去 //怎么带用户名和密码到服务器,将用户名和密码设置在请求头中 org.w3c.dom.Document document = DOMHelper.createDocument(); Element ele = document.createElement("account");//创建标签<account></account> Element eleName = document.createElement("name");//创建标签<name></name> eleName.setTextContent(name);//给<name>设值,值为客户端传进来的用户名 ele.appendChild(eleName); Element elePwd = document.createElement("password");//创建标签<password></password> elePwd.setTextContent(password);//给<password>设值,值为客户端传进来的密码 ele.appendChild(elePwd); //设置标签<account>的account headers.add(new Header(new QName("account"),ele)); //如果拦截了,打印以下信息! System.out.println("客户端拦截了"); } }
***添加自定义拦截器到客户端出拦截器中*** public class TestWebService { public static void main(String[] args) { HelloWSImplService factory = new HelloWSImplService(); HelloWSImpl helloWSImpl = factory.getHelloWSImplPort(); //设置用户名和密码 String name = "webService"; String password = "123456"; //在调用服务器方法前配置拦截器 //获取发送请求的客户端对象 Client client = ClientProxy.getClient(helloWSImpl); //添加自定义拦截器到客户端出拦截器中 List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors(); outInterceptors.add(new AccountInterceptor(name,password)); String result = helloWSImpl.sayHello("webService"); System.out.println(result); } }
*****************以上是客户端********************
*****************以上是服务器********************
//服务器拦截器 public class CheckAccountInterceptor extends AbstractPhaseInterceptor<SoapMessage>{ public CheckAccountInterceptor() { super(Phase.PRE_PROTOCOL); } @Override public void handleMessage(SoapMessage message) throws Fault { //获取客户端请求头 //account为客户端设置的qname Header header = message.getHeader(new QName("account")); if(header != null){ Element account = (Element) header.getObject(); //通过标签名获取值<name></name> String name = account.getElementsByTagName("name").item(0).getTextContent(); String password = account.getElementsByTagName("password").item(0).getTextContent(); if("webService".equals(name) && "123456".equals(password)){ System.out.println("验证通过......"); } } System.out.println("没有通过拦截器!"); throw new Fault(new RuntimeException("用户名或者密码错误!")); } }
//将自定义拦截器添加到服务器的入拦截器 public class RealeaseWS { public static void main(String[] args) { String address = "http://localhost:8989/WebService_Server"; Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl()); EndpointImpl endpointImpl = (EndpointImpl)endpoint; //将自定义拦截器添加到服务器的入拦截器 List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors(); inInterceptors.add(new CheckAccountInterceptor()); System.out.println("webService发布成功!"); } }
运行程序:
如果没有通过,则出现以下信息:
客户端拦截了
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: 用户名或者密码错误!
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:156)
at com.sun.proxy.$Proxy27.sayHello(Unknown Source)
at com.test.TestWebService.main(TestWebService.java:34)
Caused by: org.apache.cxf.binding.soap.SoapFault: 用户名或者密码错误!