基于CXF的WebService(4、客户端调用改进、拦截器使用)


placeholder image
admin 发布于:2013-03-28 22:08:00
阅读:loading

前面说到客户端调用代码封装(实现方式为代理),觉得那次封装的有些问题,其实现是继承JaxWsProxyFactoryBean,将其相关的函数封装,现在想想此种实现在别人调用的时候会有混乱的情况,比如搞不清楚哪个是封装的,哪些是代理自身的,且在调用封装代码的时候,由于eclipse的提示功能会自动带出基类自身的函数,挺不爽的。这次将客户端调用优化一下,且添加拦截器的实现。

CXF提供了大量的拦截器实现,网上很多地方都说掌握它的自身拦截器就能实现一些常用的功能。这里说的拦截器也是一些简单的,比如:将接口调用的输入、响应的报文(分别指我调用你接口时传递的数据和调用完毕后你返回给我的数据)输出至控制台、文件。

注:自定义拦截器先不谈,有些还没搞清楚,下回再说;基于sping的配置文件添加拦截器的也不说,跟代码是差不太多。

在接口调用的时候,特别是涉及到多个系统之间调用时,报文就显的异常重要了,出现什么问题,拿报文说话,问题表现的也很直观,废话少说,说下怎么实现。

使用自带的输入、响应拦截器实现(LoggingInInterceptorLoggingOutInterceptor),如果对这块有相关的了解,其实看下这两个拦截器的源码就能大概猜到,如下代码:

public voidhandleMessage(Message message) throws Fault {

   Logger logger = getMessageLogger(message);

   if(writer!= null|| logger.isLoggable(Level.INFO)) {

        logging(logger, message);

   }

}

通过构造函数传递了PrintWriter参数或日志级别为INFO时输出日志至控制台。

通过我的实现总结了两种方式实现输出报文至控制台:

1、     直接实例化LoggingXXInterceptor类,通过代理工厂获取连接池链,然后再add一下。

2、    实例化的时候,使用该System.out参数构造对象,即告诉它将数据输出值控制台。

两种方式实现将报文输出至文件:

1、    实例化的时候,使用new PrintWriter(new File(“f:\\tt.txt”));

2、    使用无参构造的对象,调用如下函数:outIntercept.setOutputLocation("file:///f:/aaa.txt");此处需要注意:看下源码能知道如果传递了此参数,则将报文输出值改处指向的问题,不过此处的参数时URI类型的,跟new File(URI)此参数一样,基本上很少使用过此构造吧,URI支持的地址为:
file:///aaa.txt
或者
../../demo/Hello.java

根据上面的描述和代码的封装,借助于腾讯QQ在线状态 WEB 服务 来实现一个小例子,详细代码如下:

    public static void main(String[] args) throws Exception {

      //获取spring上下文

        ClassPathXmlApplicationContextcontext = newClassPathXmlApplicationContext("applicationContext.xml");

      //获取代理接口实现类

        WsClientFactory<?>factory = context.getBean("wsClientFactory",WsClientFactory.class);

        PrintWriterinPrint = newPrintWriter("f:\\a_in.xml");

        LoggingInInterceptorinInterceptor = newLoggingInInterceptor(inPrint);

        factory.addInInterceptors(inInterceptor);//添加被调用端响应的数据

        PrintWriteroutPrint = newPrintWriter("f:\\a_out.xml");

        LoggingOutInterceptoroutInterceptor = newLoggingOutInterceptor(outPrint);

        factory.addOutInterceptors(outInterceptor);//添加调用端传输的数据

        QqOnlineWebServiceSoapservice = factory.getWsClientService("com.ws.qq.QqOnlineWebServiceSoap");

       //也可以调用此函数,直接添加调用的拦截器          //factory.getWsClientService("com.ws.qq.QqOnlineWebServiceSoap",inInterceptor, outInterceptor);

        Stringresult = service.qqCheckOnline("271069593");//调用服务端接口实现

        System.out.println("qq状态:" + result);

        inPrint.flush();

        inPrint.close();

        outPrint.flush();

        outPrint.close();

   } 
说明:上面的代码大多数都是为了拦截器的,一大堆垃圾代码,真正调用的就那么两行。刨去构造对象的那些,真正也没多少了,或者说可以再封装。 

附:
基于代理的服务端代码添加拦截器:

    JaxWsServerFactoryBean factory = newJaxWsServerFactoryBean();

    factory.setServiceClass(HelloService.class);

    factory.setAddress("/helloService");

    factory.getInInterceptors().add(newLoggingInInterceptor());

    Server server = factory.create();

    server.start(); 

来个运行效果图,将接口调用的报文信息保存至文件中,如下:

运行效果图-含水印.gif


此图为内涵图,将图片存储到本地,使用压缩包打开,即可以找到源码。
===============分割线===============
@2014-05-01
1、在服务端添加拦截器的过程中,in或者request为客户端输入传递的参数,out或者response为服务端响应给客户端的结果。 

 2、在客户端添加拦截器的过程中,与上述相反out为客户端传递给服务端的数据,in为服务端输出的响应。
3、值得一提的是使用拦截器给所有的接口加上一层权限或者说是安全性的校验,统一添加一些约定好的账户密码或者用户角色,使得这些与外部系统间交互的接口更加健壮。
4、最新的代码下载,懒得上传了,有问题再议。 


 点赞


 发表评论

当前回复:作者

 评论列表


留言区