把客户端的请求、拦截器和服务器端的响应、拦截器配置在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入拦截器先拦截到客户端发送的请求,执行拦截器,解析请求头中的用户名和密码是否正确,正确,然后执行服务器端的服务,把响应结果返回给客户端。
服务器端工程:
客户端工程: