WebService学习总结(4)拦截器和自定义拦截器

1、什么是拦截器?

拦截器分为Service端Client端。 拦截器是在发送soap消息包的某一个时机拦截soap消息包,对soap消息包的数据进行分析或处理。分为CXF自带的拦截器自定义的拦截器

CXF自带的拦截器:

       LoggingInInterceptor(系统日志入拦截器类)

       LoggingOutInterceptor(系统日志出拦截器类)

下面一张图可以形象的表现出拦截器的实现原理。

1.1拦截器链的阶段:

拦截器链有多个阶段,每个阶段都有多个拦截器。拦截器在拦截器链的哪个阶段起作用,可以在拦截器的构造函数中声明。 
输入拦截器链有如下几个阶段,这些阶段按照在拦截器链中的先后顺序排列。

阶段名称 阶段功能描述
RECEIVE Transport level processing(接收阶段,传输层处理)
(PRE/USER/POST)_STREAM Stream level processing/transformations(流处理/转换阶段)
READ This is where header reading typically occurs(SOAPHeader读取)
(PRE/USER/POST)_PROTOCOL Protocol processing, such as JAX-WS SOAP handlers(协议处理阶段,例如JAX-WS的Handler处理)
UNMARSHAL Unmarshalling of the request(SOAP请求解码阶段)
(PRE/USER/POST)_LOGICAL Processing of the umarshalled request(SOAP请求解码处理阶段)
PRE_INVOKE Pre invocation actions(调用业务处理之前进入该阶段)
INVOKE Invocation of the service(调用业务阶段)
POST_INVOKE Invocation of the outgoing chain if there is one(提交业务处理结果,并触发输入连接器)


输出拦截器链有如下几个阶段,这些阶段按照在拦截器链中的先后顺序排列。

阶段名称 阶段功能描述
SETUP Any set up for the following phases(设置阶段)
(PRE/USER/POST)_LOGICAL Processing of objects about to marshalled
PREPARE_SEND Opening of the connection(消息发送准备阶段,在该阶段创建Connection)
PRE_STREAM 流准备阶段
PRE_PROTOCOL Misc protocol actions(协议准备阶段)
WRITE Writing of the protocol message, such as the SOAP Envelope.(写消息阶段)
MARSHAL Marshalling of the objects
(USER/POST)_PROTOCOL Processing of the protocol message
(USER/POST)_STREAM Processing of the byte level message(字节处理阶段,在该阶段把消息转为字节)
SEND 消息发送


在CXF中,所有对消息的处理都是通过各种拦截器实现。CXF已经实现了多种拦截器,如操纵消息头、执行认证检查、验证消息数据、日志记录、消息压缩等,有些拦截器在发布服务、访问服务时已经默认添加到拦截器链。

注意: jdk写的程序不支持拦截器,需要使用cxf框架,导入cxf的jar包

1.2拦截器能干吗?

我们知道webservice是实现两个系统之间的交互,服务器在接受客户端传来的请求时,必然需要去验证其是否具有权限操作。

 通常呢,我们是把验证信息放在soapmessage的头信息中。比如说实现用户的登录验证等等。或者更加深入的是拦截器其实内部之间是可以相互通讯的。

2、查看CXF自带的拦截器

2.1  服务器端实现

package com.ws.service;

import javax.xml.ws.Endpoint;


import com.sun.xml.internal.ws.transport.http.server.EndpointImpl;
import com.ws.HelloWSImpl;

public class ServerTest {

	public static void main(String[] args) {
	
		String address="http://localhost:8080/WS_day_01/HelloWS/sayHello";
		//调用Endpoint的publish方法
		EndpointImpl ep=(EndpointImpl)Endpoint.publish(address, new HelloWSImpl());
		 
				/*ep.getInInterceptors().add(new LoggingInInterceptor());
				ep.getInInterceptors().add(new LoggingInInterceptor());*/
		System.out.println("发布成功");
	}

}

2.2  客户端实现

package com.ws.service;

import javax.xml.ws.Endpoint;

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;

import com.ws.HelloWSImpl;


public class ServerTest {

	public static void main(String[] args) {
	
		String address="http://localhost:8080/WS_day_01/HelloWS/sayHello";
		//调用Endpoint的publish方法
		EndpointImpl ep=(EndpointImpl)Endpoint.publish(address, new HelloWSImpl());
		ep.getInInterceptors().add(new LoggingInInterceptor());
		ep.getInInterceptors().add(new LoggingInInterceptor());
		System.out.println("发布成功");
	}

}

2.3输出结果是:

客户端:

服务器端:

3、自定义拦截器

3.1 服务器端

package com.ws.intecepter;
 
import java.util.List;
 
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;
import org.w3c.dom.NodeList;
 
/**
 * 自定义拦截器,需要继承 AbstractPhaseInterceptor
 * 通过PhaseInterceptor,可以指定拦截器在哪个阶段起作用
 * @author SAM
 *
 */
public class MyIntecepter extends AbstractPhaseInterceptor<SoapMessage> {
	
	/*
	 * 一定要自己定义一个构造器
	 */
	public MyIntecepter() {
		
		/*
		 * 父类构造器中参数String phase,为在哪个阶段调用拦截器
		 * Phase.PRE_INVOKE在调用之前调用拦截器
		 */		
		super(Phase.PRE_INVOKE);
	}
	
	/* 实现自己的拦截器时,需要实现handleMessage方法
	 * handleMessage方法中的形参就是被拦截到的SOAP消息
	 * 一旦程序获得了这个soap消息,剩下的事情就可以解析soap消息,或修改soap消息
	*/
	public void handleMessage(SoapMessage msg) throws Fault {
		System.out.println("++++拦++++截++++器++++开++++始++++调++++用++++");		
		
//		System.out.println("=========================== \n"+ msg+"\n ========================");	
		
		List<Header> headers = msg.getHeaders();
		if(headers==null || headers.size()<1) {
			throw new Fault(new IllegalArgumentException("根本没有Header,别想调用"));
		}
		
		//假如要求第一个Header携带了用户名、密码信息
		Header firstHeader = headers.get(0);
		Element element = (Element) firstHeader.getObject();
		
		NodeList userids = element.getElementsByTagName("userId");
		NodeList userPasses = element.getElementsByTagName("userPass");
		
		if(userids.getLength()!=1) {
			throw new Fault(new IllegalArgumentException("用户名格式不对"));
		}
		
		if(userPasses.getLength()!=1) {
			throw new Fault(new IllegalArgumentException("密码格式不对"));
		}
		
		//得到第一个userId元素的文本内容,以该内容作为用户名字
		String userId = userids.item(0).getTextContent();
		String userPass = userPasses.item(0).getTextContent();
		
		//实际项目中,应该去查询数据库,该用户名、密码是否被授权
		if(userId.equals("冯冬冬")) {
			//throw new Fault(new IllegalArgumentException("---------用---户----名---不----正-----确---------!!!!"));
			System.out.println("拦截器内部用户名正确");
		}
		if(userPass.equals("123456")) {
			//throw new Fault(new IllegalArgumentException("--------密---码-----不-----正------确-------!!!!!"));
			System.out.println("拦截器内部密码正确");
		}
		
		System.out.println("拦++++截++++器++++结===============束++++");	
	}
 
}

接下来添加自己的拦截器” 

package com.ws.publish;

import javax.xml.ws.Endpoint;

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;


import com.ws.impl.HelloWorldImpl;
import com.ws.intecepter.MyIntecepter;


/** 
 * 类描述: 
 *@author: 冯冬冬 
 *@date: 日期:2018-7-25 时间:上午9:41:41 
 */
public class PublishTest {
	public static void main(String[] args) {
		System.out.println("Server start ……");
		 
		HelloWorldImpl service = new HelloWorldImpl();
		String address = "http://127.0.0.1:8888/helloWorld";
 
		// 调用Endpoint的publish方法
		EndpointImpl ep=(EndpointImpl)Endpoint.publish(address, service);
 
		//在服务器端添加自带拦截器
		//ep.getInInterceptors().add(new LoggingInInterceptor());
		//ep.getInInterceptors().add(new LoggingInInterceptor());
		
        //添加自定义拦截器
		ep.getInInterceptors().add(new MyIntecepter());
		System.out.println("server ready ……");
	}

}

3.2 客户端

/**
 * 
 */
package com.ws.intecepter;


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.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/** 
 * 类描述: 
 *@author: 冯冬冬 
 *@date: 日期:2018-7-25 时间:下午2:41:38 
 */

public class MyClientIntecepter extends AbstractPhaseInterceptor<SoapMessage> {
	
	private String userId;
	private String userPass;
	
	//构造器
	public MyClientIntecepter(String userId, String userPass) {
		super(Phase.PREPARE_SEND);//发送消息前调用
		this.userId = userId;
		this.userPass = userPass;
	}
	
	// 实现的方法
	public void handleMessage(SoapMessage msg) throws Fault {
		System.out.println("=================客 户 端   内部拦截器调用   开  始================");
		List<Header> headers = msg.getHeaders();//得到soap消息的header
		
		//创建document对象
		Document document = DOMUtils.createDocument();
		Element header = document.createElement("MyHeader");
		
		//创建一个header元素与服务器一致
		Element userIdEle = document.createElement("userId");
		Element userPassEle = document.createElement("userPass");		
		userIdEle.setTextContent(userId);
		userPassEle.setTextContent(userPass);		
		header.appendChild(userIdEle);
		header.appendChild(userPassEle);
		System.out.println("=================客 户 端   内部拦截器调用  结  束================");
		headers.add(new Header(new QName("冯冬冬"), header));//把header放入soap的
		
	}
 
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserPass() {
		return userPass;
	}
	public void setUserPass(String userPass) {
		this.userPass = userPass;
	}
 
}

接下来在客户端添加自定义拦截器:

package com.ws.test;


import java.util.List;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;

import com.ws.Cat;
import com.ws.HelloWorld;
import com.ws.User;
import com.ws.impl.HelloWorldImplService;
import com.ws.intecepter.MyClientIntecepter;

/** 
 * 类描述: 
 *@author: 冯冬冬 
 *@date: 日期:2018-7-25 时间:上午10:33:30 
 */
public class TestClient {

	public static void main(String[] args) {
		HelloWorldImplService factory=new HelloWorldImplService();
		HelloWorld hw=factory.getHelloWorldImplPort();	
		
		Client client = ClientProxy.getClient(hw);
		/*// 客户端 增加拦截器。这里是使用的自带的拦截器
	
		client.getInInterceptors().add(new LoggingInInterceptor());
		client.getOutInterceptors().add(new LoggingOutInterceptor());*/	
		//下面使用自定义的拦截器
		client.getOutInterceptors().add(new MyClientIntecepter("冯冬冬","123456"));
		System.out.print(""+hw.sayHi("张三"));
	}

}

3.3 输出结果

首先看客户端:

接下来看服务器端:

总结:拦截器的主要作用就是实现权限拦截。对用户的非法操作进行拦截。基本上就介绍到这里

猜你喜欢

转载自blog.csdn.net/SDDDLLL/article/details/81211234
今日推荐