(五)整合spring与cxf的拦截器

把客户端的请求、拦截器和服务器端的响应、拦截器配置在spring的容器中,当有客户端发出请求时,自动执行拦截器和服务器的响应。
下面演示示例:客户端发出请求时,客户端的出拦截器在把用户名和密码加在请求头中;服务器端入拦截器解析请求头中是否有指定的用户名和密码,如果有执行服务器响应。

一、服务器开发

1、建立一个动态工程webservice-cxf-spring-interceptor-server,把cxf框架中lib目录下的jar包烤到工程下的/WebContent/WEB-INF/lib目录中,并导入工程中。web.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>webservice-cxf-spring-interceptor-server</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>

    <!-- 配置beans.xml,指定bean.xml的加载位置-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:beans.xml</param-value>
  </context-param>

  <!-- 应用启动的一个监听器,监听webservice的请求和响应时,当有请求和响应时就用cxf的框架进行处理 -->
  <listener>
    <listener-class>
         org.springframework.web.context.ContextLoaderListener
      </listener-class>
  </listener>

  <!-- 表示所有请求都会先经过cxf框架 -->
  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>
         org.apache.cxf.transport.servlet.CXFServlet
      </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

</web-app>

2、在src目录下创建spring的配置文件bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

    <!-- 引入cxf的一些核心配置 -->
    <!-- 
    cxf.xml配置cxf的一些核心处理器;
    cxf-extension-soap.xml配置cxf的一些扩展功能;
    cxf-servlet.xml用于自定义cxf的特性,默认为空
     -->
   <import resource="classpath:META-INF/cxf/cxf.xml" /> 
   <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
   <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> 

   <!-- 用来发布服务 -->
   <!-- 
    address表示服务的地址,本例为http://localhost:8080/webservice-cxf-spring-interceptor-server/userService;
    对应的wsdl地址为http://localhost:8080/webservice-cxf-spring-interceptor-server/userService?wsdl
    -->
   <jaxws:endpoint 
     id="userService" 
     implementor="com.lzj.webservice.ws.UserServiceImpl" 
     address="/userService">

     <!--配置服务器端的入拦截器-->
     <jaxws:inInterceptors>
        <bean class="com.lzj.webservice.ws.interceptor.CheckUserInterceptor"></bean>
     </jaxws:inInterceptors>

    </jaxws:endpoint>
</beans>

3、创建服务端的服务,用于响应客户端的请求,并把请求配置到bean.xml中。
服务接口:

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

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

服务接口实现:

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

@WebService
public class UserServiceImpl implements UserService {

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

}

4、创建拦截器,并把拦截器配置到bean.xml中

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;

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("用户名或密码不合法……");
        }
    }
}

二、客户端开发

1、建立一个动态工程webservice-cxf-spring-interceptor-client,把cxf框架中lib目录下的jar包烤到工程下的/WebContent/WEB-INF/lib目录中,并导入工程中。在cmd中用wsdl2java命令生成客户端代码

wsdl2java http://localhost:8080/webservice-cxf-spring-interceptor-server/userService?wsdl

生成代码如下:
这里写图片描述

2、创建客户端的拦截器,并装配到bean.xml中

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(name);
        rootElement.appendChild(nameElement);
        Element passwordElement = document.createElement("password");
        passwordElement.setTextContent(password);
        rootElement.appendChild(passwordElement);

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

}

3、创建spring的配置文件bean.xml,配置客户端的请求和拦截器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置客户端的请求 -->
    <jaxws:client id="userService" 
        serviceClass= "com.lzj.webservice.ws.UserService" 
        address= "http://localhost:8080/webservice-cxf-spring-interceptor-server/userService">

        <!-- 配置客户端的出拦截器 -->
        <jaxws:outInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
            <bean class="com.lzj.webservice.ws.interceptor.AddUserInterceptor">
                <constructor-arg name="name" value="lzj"></constructor-arg>
                <constructor-arg name="password" value="123456"></constructor-arg>
            </bean>
        </jaxws:outInterceptors>

    </jaxws:client>

</beans>

4、创建客户端的测试方法,用于向服务器端发送请求

package com.lzj.cxf.spring.client.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.lzj.webservice.ws.UserService;

public class ClientTest {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = 
                new ClassPathXmlApplicationContext(new String[]{"classpath:bean.xml"});
        UserService userService = (UserService) context.getBean("userService");
        String result = userService.sayHello("lzj");
        System.out.println(result);
    }

}

<响应结果>

首先启动服务器端工程,然后运行客户端的测试方法

客户端输出日志如下:

……
客户端拦截器开始执行……
二月 24, 2018 10:14:39 下午 org.apache.cxf.services.UserServiceService.UserServicePort.UserService
信息: Outbound Message
---------------------------
ID: 1
Address: http://localhost:8080/webservice-cxf-spring-interceptor-server/userService
Encoding: UTF-8
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><customer><name>lzj</name><password>123456</password></customer></soap:Header><soap:Body><ns2:sayHello xmlns:ns2="http://ws.webservice.lzj.com/"><arg0>lzj</arg0></ns2:sayHello></soap:Body></soap:Envelope>
--------------------------------------
hello lzj

从日志可以看出,客户端配置的AddUserInterceptor自定义出拦截器先拦截到客户端发送的请求,执行拦截器,把用户名和密码加到请求的头中, 然后客户端配置的LoggingOutInterceptor系统日志出拦截器先拦截客户端的发送请求,打印出请求日志,最后服务端响应后返回响应的数据。

服务器端的输出日志如下:

……
通过服务器端拦截器……
hello:lzj

服务器端配置的自定义的CheckUserInterceptor入拦截器先拦截到客户端发送的请求,执行拦截器,解析请求头中的用户名和密码是否正确,正确,然后执行服务器端的服务,把响应结果返回给客户端。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值