【WebService框架-CXF】——CXF拦截器
2016-06-20 18:05
344 查看
背景
当一个服务发布之后,只要有服务地址,我们就可以建立客户端对服务进行调用。如果服务的提供者想要对可以调用服务的客户端进行限制,如:只有某些客户可以调用此服务。这时候就会用到拦截器,来进行权限控制。明白了拦截器的应用场景,我们看看CXF的拦截器怎么用。
IN&OUT拦截器
从图中我们可以总结出,只要从一端发出消息时要进行拦截,就要使用OUT拦截器。如果要对接收的消息进行拦截就要使用IN拦截器。
在服务端添加IN拦截器和OUT拦截器
public class TestMain { public static void main(String[] arg){ HelloWorld hw=new HelloWorldWS(); EndpointImpl eImpl=(EndpointImpl)Endpoint.publish("http://localhost:9009/HelloWorldWS", hw); eImpl.getInInterceptors().add(new LoggingInInterceptor()); eImpl.getOutInterceptors().add(new LoggingOutInterceptor()); System.out.println("Web Service暴露成功!"); } }
调用客户端,之后在服务端查看打印结果
Inbound Message
通过LoggingInInterceptor()拦截到的信息
六月 18, 2016 9:18:40 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log 信息: Inbound Message ---------------------------- ID: 3 Address: http://localhost:9009/HelloWorldWS Encoding: UTF-8 Http-Method: POST Content-Type: text/xml; charset=UTF-8 Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[185], content-type=[text/xml; charset=UTF-8], Host=[localhost:9009], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 2.4.0]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi xmlns:ns2="http://ws.tgb.com/"><arg0>许晨阳</arg0></ns2:sayHi></soap:Body></soap:Envelope>
Outbound Message
通过LoggingOutInterceptor()拦截到的信息
六月 18, 2016 9:18:40 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log 信息: Outbound Message --------------------------- ID: 3 Encoding: UTF-8 Content-Type: text/xml Headers: {} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse xmlns:ns2="http://ws.tgb.com/"><return>许晨阳,你好!现在时间是:2016-06-18 09:18:40</return></ns2:sayHiResponse></soap:Body></soap:Envelope>
在客户端添加IN拦截器和OUT拦截器
此时相同的信息会在客户端打印出来。
public class ClientMain { public static void main(String[] args){ //工厂,继承Service HelloWorldWS factory=new HelloWorldWS(); //只是服务的代理 HelloWorld hw=factory.getHelloWorldWSPort(); //客户端拦截器 Client c= ClientProxy.getClient(hw); c.getInInterceptors().add(new LoggingInInterceptor()); c.getOutInterceptors().add(new LoggingOutInterceptor()); System.out.println(hw.sayHi("许晨阳")); } }
-------------------------------------- 六月 20, 2016 5:33:43 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log 信息: Outbound Message --------------------------- ID: 1 Address: http://localhost:9009/HelloWorldWS Encoding: UTF-8 Content-Type: text/xml Headers: {Accept=[*/*], SOAPAction=[""]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi xmlns:ns2="http://ws.tgb.com/"><arg0>许晨阳</arg0></ns2:sayHi></soap:Body></soap:Envelope>
-------------------------------------- 六月 20, 2016 5:33:43 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log 信息: Inbound Message ---------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml;charset=UTF-8 Headers: {Content-Length=[252], content-type=[text/xml;charset=UTF-8], Server=[Jetty(7.3.1.v20110307)]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse xmlns:ns2="http://ws.tgb.com/"><return>许晨阳,你好!现在时间是:2016-06-20 05:33:43</return></ns2:sayHiResponse></soap:Body></soap:Envelope>
自定义拦截器
通过自定义拦截器,我们可以根据需求修改SOAP消息,进行权限控制。public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> { public AuthInterceptor(String phase) { super(phase); } @Override public void handleMessage(SoapMessage soapMessage) throws Fault { List<Header> headers=soapMessage.getHeaders(); if(headers==null || headers.size()<1){ throw new Fault(new IllegalArgumentException("没有Header,不能调用")); } Header firstHeader=headers.get(0); Element ele=(Element)firstHeader.getObject(); NodeList userIds=ele.getElementsByTagName("userId"); NodeList pwds=ele.getElementsByTagName("pwd"); if(userIds==null || userIds.getLength()!=1){ throw new Fault(new IllegalArgumentException("用户名格式不对!")); } if(pwds==null || pwds.getLength()!=1){ throw new Fault(new IllegalArgumentException("密码格式不对!")); } String userId=userIds.item(0).getTextContent(); String pwd=pwds.item(0).getTextContent(); if(!userId.equals("1") ||!pwd.equals("123")){ throw new Fault(new IllegalArgumentException("用户名和密码不对!")); } } }
在这个拦截器中,首先判断是SOAP消息中是否有Header,如果有,再判断用户名和密码是否正确。
此时,要将自定义的拦截器添加到InInterceptors,并传入一个Phase的字符串参数。
public class TestMain { public static void main(String[] arg){ HelloWorld hw=new HelloWorldWS(); //hw.sayHi("许晨阳"); EndpointImpl eImpl=(EndpointImpl)Endpoint.publish("http://localhost:9009/HelloWorldWS", hw); eImpl.getInInterceptors().add(new LoggingInInterceptor()); eImpl.getOutInterceptors().add(new LoggingOutInterceptor()); //自定义拦截器 eImpl.getInInterceptors().add(new AuthInterceptor(Phase.PRE_INVOKE)); System.out.println("Web Service暴露成功!"); } }
此时,如果客户端直接调用,会无法调用。
六月 20, 2016 5:51:24 下午 org.apache.cxf.interceptor.AbstractLoggingInterceptor log 信息: Inbound Message ---------------------------- ID: 1 Response-Code: 500 Encoding: UTF-8 Content-Type: text/xml;charset=UTF-8 Headers: {Content-Length=[222], content-type=[text/xml;charset=UTF-8], Server=[Jetty(7.3.1.v20110307)]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>没有Header,不能调用</faultstring></soap:Fault></soap:Body></soap:Envelope> -------------------------------------- Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: 没有Header,不能调用 at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:146) at com.sun.proxy.$Proxy23.sayHi(Unknown Source) at com.tgb.ws.ClientMain.main(ClientMain.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Caused by: org.apache.cxf.binding.soap.SoapFault: 没有Header,不能调用
此时返回到客户端的SOAP消息为
<soap:Fault>。
所以我们要在客户端也添加拦截器将用户名和密码添加到SOAP消息的Header中。
public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> { private String userId; private String pwd; public AddHeaderInterceptor(String userId, String pwd) { super(Phase.PREPARE_SEND); this.userId=userId; this.pwd=pwd; } @Override public void handleMessage(SoapMessage soapMessage) throws Fault { List<Header> headers= soapMessage.getHeaders(); System.out.println(headers.size()); Document doc= DOMUtils.createDocument(); Element ele=doc.createElement("authHeader"); Element eleUser=doc.createElement("userId"); eleUser.setTextContent(userId); Element elePwd=doc.createElement("pwd"); elePwd.setTextContent(pwd); ele.appendChild(eleUser); ele.appendChild(elePwd); Header header=new Header(new QName("http://impl.ws.tgb.com/"),ele); headers.add(header); System.out.println(headers.size()); } }
public class ClientMain { public static void main(String[] args){ //工厂 HelloWorldWS factory=new HelloWorldWS(); //只是服务的代理 HelloWorld hw=factory.getHelloWorldWSPort(); //客户端拦截器 Client c= ClientProxy.getClient(hw); c.getInInterceptors().add(new LoggingInInterceptor()); c.getOutInterceptors().add(new AddHeaderInterceptor("1","123")); c.getOutInterceptors().add(new LoggingOutInterceptor()); System.out.println(hw.sayHi("许晨阳")); } }
需要注意的是,我们要把此拦截器添加到客户端的OutInterceptors,这个和服务端不一样。
总结
CXF拦截器可以让我们修改SOAP消息,并在此基础上对客户端进行权限控制,很方便。相关文章推荐
- HG255D网页摄像头配置
- 游标的使用
- Office在线预览及PDF在线预览的实现方式大集合
- java设计模式之装饰模式
- 移动端常见的一些兼容性问题
- Mac使用zsh导致maven命令无效的解决方案
- NodeMCU文档中文翻译 2 首页
- 友盟开发APi(统一APK数)
- 指针、链表的原理和各类操作相关心得以及学生信息管理系统
- 触动人心的手机端页面设计
- Android EditText密码框中字体和普通的输入框不同
- STL之deque
- Office Word 是如何根据字体的 OS/2 表等信息计算「单倍行距」的
- C语言 学生宿舍管理系统
- KNN算法在保险业精准营销中的应用
- 41、JavaScript的运动----运动的终止条件
- spark-submit工具参数说明
- 绿色版mysql安装过程
- 个人界面 < 头像 > 图像添加,其他颜色的边框(内外都可以)
- Linux命令学习手册-wc命令