(三)cxf的拦截器使用

在webservice的客户端和服务端的请求和响应的过程中,能动态的操作请求和响应的数据,能够拦截请求和响应的数据并进行响应的操作,设计了cxf的拦截器,注意JDK中支持webservice,但不支持拦截器,所以开发强大的webservice通信,推荐cxf框架。

拦截器分类:
1. 按所处的位置分:服务器端拦截器,客户端拦截器
2. 按消息的方向分:入拦截器,出拦截器
3. 按定义者分:系统拦截器,自定义拦截器
如果在客户端设置了出拦截器,客户端在发送请求之前先被拦截器执行,然后发送请求;如果服务器端设置了入拦截器,服务器端在接收客户端的请求之前,先被拦截器执行,然后执行服务器端的服务。
下面以系统拦截器和自定义拦截器为例,分别在客户端和服务器端定义入拦截器和出拦截器。

一、系统拦截器

以日志拦截器为例,如果在服务端的入方向和出方向都添加日志拦截器,则在服务器端接收响应和返回给客户端结果时都会打印出日志信息。
<一>服务器端

1、 创建服务器端响应客户端的服务接口

package com.lzj.webservice.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface Webservice {   
    @WebMethod
    public String sayHello(String name);
}

2、 创建服务器端接口的实现

package com.lzj.webservice.ws;
import javax.jws.WebService;

@WebService
public class WebserviceImpl implements Webservice {

    @Override
    public String sayHello(String name) {
        System.out.println("hello:" + name);
        return "hello " + name;
    }

}

3、 把cxf框架下lib包下的jar包导入服务器端工程中,并创建测试程序,用于发布服务器端的服务,在发布服务时,设置系统自带的日志入拦截器LoggingInInterceptor 和出拦截器LoggingOutInterceptor。

package com.lzj.webservice.ws.test;
import java.util.List;
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.jaxws22.EndpointImpl;
import org.apache.cxf.message.Message;
import com.lzj.webservice.ws.WebserviceImpl;

public class WebservicePublish {

    public static void main(String[] args) {

        String address = "http://localhost:8989/Webservice-cxf-server1/webservice";
        Endpoint endpoint = Endpoint.publish(address, new WebserviceImpl());
        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成功");
    }

}

<二>客户端
1、 生成客户端代码
在cmd中通过wadl2java工具生成客户端代码,首先进入客户端工程的src目录下,用如下命令生成代码
wsdl2java http://localhost:8989/Webservice-cxf-server1/webservice?wsdl
生成代码如下:
这里写图片描述
2、把cxf框架下lib包中的jar包导入到客户端工程中,并创建测试程序,用于请求服务器端服务,并设置系统自带的出拦截器LoggingOutInterceptor。

package com.lzj.webservice.ws.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.lzj.webservice.ws.Webservice;
import com.lzj.webservice.ws.WebserviceImplService;

public class WsClient {

    public static void main(String[] args) {
        WebserviceImplService factory = new WebserviceImplService();
        Webservice ws = factory.getWebserviceImplPort();
        //获取发送请求的客户端对象
        Client client = ClientProxy.getClient(ws);
        //添加客户端的出拦截器
        List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
        outInterceptors.add(new LoggingOutInterceptor());

        String result = ws.sayHello("lzj");
        System.out.println("result : " + result);
    }

}

<服务器端客户端的运行结果>
首先运行服务器端程序,然后再运行客户端程序

客户端中输出如下内容:

ID: 1
Address: http://localhost:8989/Webservice-cxf-server1/webservice
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://ws.webservice.lzj.com/"><arg0>lzj</arg0></ns2:sayHello></soap:Body></soap:Envelope>
--------------------------------------
result : hello lzj

从输出中的日志可以看出,如果客户端设置了日志出拦截器,当客户端向服务器端发送请求时,日志出拦截器拦截到了请求,并把请求打印出来了,包括请求的地址、请求头、请求体等,然后输出的服务器端返回的数据。如果不定义拦截器就不会打印请求信息。

服务器端输出日志如下:

发布webservice成功
二月 21, 2018 10:35:31 下午 org.apache.cxf.services.WebserviceImplService.WebserviceImplPort.Webservice
信息: Inbound Message
----------------------------
ID: 1
Address: http://localhost:8989/Webservice-cxf-server1/webservice?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]}
--------------------------------------
二月 21, 2018 10:35:32 下午 org.apache.cxf.services.WebserviceImplService.WebserviceImplPort.Webservice
信息: Inbound Message
----------------------------
ID: 2
Address: http://localhost:8989/Webservice-cxf-server1/webservice
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[196], 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://ws.webservice.lzj.com/"><arg0>lzj</arg0></ns2:sayHello></soap:Body></soap:Envelope>
--------------------------------------
hello:lzj
二月 21, 2018 10:35:32 下午 org.apache.cxf.services.WebserviceImplService.WebserviceImplPort.Webservice
信息: Outbound Message
---------------------------
ID: 2
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://ws.webservice.lzj.com/"><return>hello lzj</return></ns2:sayHelloResponse></soap:Body></soap:Envelope>
--------------------------------------

从日志中可以看出,先执行的日志入拦截器,然后执行的服务器端响应服务,最后执行的日志出拦截器。

服务器端工程目录:
这里写图片描述

客户端工程目录:
这里写图片描述

二、自定义拦截器

使用自定义拦截器实现用户名与密码的校验。服务器端设置入拦截器,客户端设置出拦截器。
<一>服务器端
1、 定义响应客户端的服务接口

package com.lzj.webservice.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface Webservice {   
    @WebMethod
    public String sayHello(String name);
}

2、 创建服务接口的实现类

package com.lzj.webservice.ws;
import javax.jws.WebService;

@WebService
public class WebserviceImpl implements Webservice {

    @Override
    public String sayHello(String name) {
        System.out.println("hello:" + name);
        return "hello " + name;
    }

}

3、 把cxf框架中lib目录下的jar包导入到服务器端工程中,并创建检查用户姓名和密码的入拦截器。

package com.lzj.webservice.ws.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;

/*
自定义的拦截器都要继承AbstractPhaseInterceptor;
SoapMessage表示拦截的信息类型,因为webservice传输soap类型的消息;
Phase是一个abstract类,定义了在哪个阶段进行拦截消息
*/
public class CheckUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

    /*在准备协议阶段拦截请求*/
    private static String phase = Phase.PRE_PROTOCOL;

    public CheckUserInterceptor() {
        super(phase);
    }
    /*如果不设置拦截器,客户端准备发送请求的协议是下面的形式
    <Body>
        <sayHello>
            <arg0>lzj</arg0>
        <sayHello>
    </Body>

     现在设置拦截器,在发送请求之前,加上了用户的姓名和密码,则在准备协议时准备成了下面的形式
    <Envelope>
        <head>
            <!--头中可以添加多个内容,本例中只添加一个-->
            <customer>
                <name>lzj</name>
                <password>123456</password>
            </customer>
            <customer2>
                <name>zhangsan</name>
                <password>123456</password>
            </customer2>
        <head>
        <Body>
            <sayHello>
                <arg0>lzj</arg0>
            <sayHello>
        </Body>
    </Envelope>
    在服务器端应拦截上面xml中的head部分
 */

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        /*现在准备拦截如下内容
        <customer>
            <name>lzj</name>
            <password>123456</password>
        </customer>
         * */
        Header header = message.getHeader(new QName("customer"));
        if (header != null) {
            Element customerElement = (Element) header.getObject();
            String name = customerElement.getElementsByTagName("name").item(0).getTextContent();
            String password = customerElement.getElementsByTagName("password").item(0).getTextContent();
            if ("lzj".equals(name) && "123456".equals(password)) {
                System.out.println("通过服务器端拦截器……");
                return;
            }
            System.out.println("不能通过服务器端拦截器……");
            throw new IllegalArgumentException("用户名或密码不合法……");
        }
    }
}

4、 创建服务器端的测试程序,设置自定义的入拦截器,并发布服务。

package com.lzj.webservice.ws.test;
import java.util.List;
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.jaxws22.EndpointImpl;
import org.apache.cxf.message.Message;
import com.lzj.webservice.ws.WebserviceImpl;
import com.lzj.webservice.ws.interceptor.CheckUserInterceptor;

public class WebservicePublish {

    public static void main(String[] args) {

        String address = "http://localhost:8989/Webservice-cxf-interceptor-server/webservice";
        Endpoint endpoint = Endpoint.publish(address, new WebserviceImpl());
        EndpointImpl endpointImpl = (EndpointImpl)endpoint;
        //添加服务器端的入日志拦截器
        List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
        inInterceptors.add(new CheckUserInterceptor());
        System.out.println("发布webservice成功");
    }

}

<二>客户端
1、 生成客户端代码
在cmd中进入客户端工程的src目录,用如下命令生成代码:
Wsdl2java http://localhost:8989/Webservice-cxf-interceptor-server/webservice
生成代码如下(注意:要在运行服务器端工程的前提下,再用上述命令生成代码,否则会报一个拒绝连接的错误):
这里写图片描述

2、 把cxf框架下lib目录下的jar包导入到客户端工程中,并创建客户端的出拦截器,用于添加用户的姓名和密码。

package com.lzj.webservice.ws.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.apache.xml.utils.DOMHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class AddUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

    private String name;
    private String password;

    /*在准备协议阶段进行拦截*/
    private static String phase = Phase.PRE_PROTOCOL;

    public AddUserInterceptor(String name, String password) {
        super(phase);
        this.name = name;
        this.password = password;
    }

    /*如果不设置拦截器,客户端准备发送请求的协议是下面的形式
    <Body>
        <sayHello>
            <arg0>lzj</arg0>
        <sayHello>
    </Body>

     现在设置拦截器,在发送请求之前,要在发送的内容中加上用户的姓名和密码,则在准备协议时应准备成下面的形式
    <Envelope>
        <head>
            <!--头中可以添加多个内容,本例中只添加一个-->
            <customer>
                <name>lzj</name>
                <password>123456</password>
            </customer>
            <customer2>
                <name>zhangsan</name>
                <password>123456</password>
            </customer2>
        <head>
        <Body>
            <sayHello>
                <arg0>lzj</arg0>
            <sayHello>
        </Body>
    </Envelope>
 */

    @Override
    public void handleMessage(SoapMessage msg) throws Fault {
        List<Header> headers = msg.getHeaders();
        /*
         准备下面内容
        <customer>
            <name>lzj</name>
            <password>123456</password>
        </customer>
         * */
        Document document = DOMHelper.createDocument();
        Element rootElement = document.createElement("customer");
        Element nameElement = document.createElement("name");
        nameElement.setTextContent("lzj");
        rootElement.appendChild(nameElement);
        Element passwordElement = document.createElement("password");
        passwordElement.setTextContent("123456");
        rootElement.appendChild(passwordElement);

        headers.add(new Header(new QName("customer"), rootElement));
        System.out.println("客户端拦截器开始执行……");
    }

}

3、 创建客户端的测试程序,并设置自定义的出拦截器

package com.lzj.webservice.ws.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.lzj.webservice.ws.Webservice;
import com.lzj.webservice.ws.WebserviceImplService;
import com.lzj.webservice.ws.interceptor.AddUserInterceptor;

public class WsClient {

    public static void main(String[] args) {
        WebserviceImplService factory = new WebserviceImplService();
        Webservice ws = factory.getWebserviceImplPort();
        //获取发送请求的客户端对象
        Client client = ClientProxy.getClient(ws);
        //添加日志出拦截器
        List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
        outInterceptors.add(new AddUserInterceptor("lzj", "123456"));
        String result = ws.sayHello("lzj");
        System.out.println("result : " + result);
    }

}

<服务器端和客户端的输出结果>
先运行服务器端程序,然后运行客户端程序
客户端输出日志如下:

客户端拦截器开始执行……
result : hello lzj

由日志可以看出,客户端先执行了自定义的出拦截器,然后执行了服务器端的响应。

服务器端输出日志如下:

发布webservice成功
通过服务器端拦截器……
hello:lzj

由日志可以看出,服务器端先执行了自定义了入拦截器,然后响应客户端的请求。

客户端工程目录:
这里写图片描述

服务器工程目录:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值