JAX-WS - Handler詳解

襲冷發表於2014-06-24

一、Handler說明

    Handler用於處理Soap訊息,如控制Header(如隱式的新增使用者資訊等)

    Handler分成LogicalHandler和SOAPHandler,常用為SOAPHandler;客戶端先處理LogicalHeader再處理SOAPHandler,伺服器反之


二、開始前的準備

    1、服務端

        (1)介面:

@WebService
public interface UserService {

	@WebResult(name="registerResult")
	public String register(@WebParam(name="user") User user);
}

        (2)實現:

@WebService(endpointInterface="com.xilen.jws.UserService", serviceName="UserServiceImplService")
public class UserServiceImpl implements UserService{

	@Override
	public String register(User user) {
		System.out.println(user);
		return user.getName() + ", registered!";
	}

}
        (3)啟動:

public class StartMain {
	public static void main(String[] args) {
		Endpoint.publish("http://localhost:8888/userinfo", new UserServiceImpl());
	}
}
    2、客戶端

       (1) 通過wsimport生成相關程式碼後,呼叫服務端編碼:

public class Client {
	
	public static void main(String[] args) {
		
		UserServiceImplService usis = new UserServiceImplService();
		UserService service = usis.getUserServiceImplPort();

		User user = new User();
		user.setId(1);
		user.setName("admin");
		user.setPass("12345");
		
		System.out.println(service.register(user));
	}
}

        (2)執行

/**
* 可以完成呼叫並返回
*/
admin, registered!

三、新增Handler

    1、服務端

        (1)自定義Handler繼承SOAPHandler<T>

public class HeaderHandlerServer implements SOAPHandler<SOAPMessageContext> {

	@Override
	public boolean handleMessage(SOAPMessageContext context) {

		try {
			/**
			 * True表示Out訊息,False表示In訊息
			 */
			Boolean messageTag = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
			/**
			 * 服務端驗證,In的時候
			 */
			if(messageTag == false){
				
				SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
				
				SOAPHeader header = envelope.getHeader();
				/**
				 * 如果header為空或者沒有元素,這裡判斷是否沒有元素用的是examineAllHeaderElements()方法
				 */
				if(header == null || ! header.examineAllHeaderElements().hasNext()){
					
					SOAPFault fault = envelope.getBody().addFault();
					fault.setFaultString("驗證資訊為空!");
					
					throw new SOAPFaultException(fault);
					
				}else{
					/**
					 * 將header的所有元素提取為Iterator。需要注意的是,extractAllHeaderElements()只能在Header中提取一次
					 */
					Iterator<SOAPHeaderElement> iterator = header.extractAllHeaderElements();
					
					if(iterator.hasNext()){
						
						SOAPHeaderElement headerEle = iterator.next();
						
						/**
						 * 獲取客戶端傳遞過來的需要驗證的資訊
						 */
						System.out.println(headerEle.getTextContent());
						
						/**
						 * 後續的驗證處理
						 */
					}
				}
			}
			/**
			 *  如果Catch Exception,SOAPFaultException將不能到客戶端
			 */
		} catch (SOAPException e) {
			e.printStackTrace();
		}
		
		return true;
	}

	@Override
	public boolean handleFault(SOAPMessageContext context) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void close(MessageContext context) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Set<QName> getHeaders() {
		// TODO Auto-generated method stub
		return null;
	}

}
        (2)編輯handler-chains配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	
	<javaee:handler-chain>
		<javaee:handler>
			<javaee:handler-class>com.xilen.handler.HeaderHandlerServer</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
	
</javaee:handler-chains>
        (3)在服務上新增Handler

/**
 * 新增Header,通過在服務的實現類上註解@HandlerChain並指定其配置
 */
@WebService(endpointInterface="com.xilen.jws.UserService", serviceName="UserServiceImplService")
@HandlerChain(file="jax-handler.xml")
public class UserServiceImpl implements UserService{

	@Override
	public String register(User user) {
		System.out.println(user);
		return user.getName() + ", registered!";
	}

}
        (4)測試這個Handler的效果
/**
* 在客戶端沒有新增相關Header以攜帶使用者資訊時呼叫服務端,將在客戶端丟擲如下異常
*/
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: 驗證資訊為空!
	at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(Unknown Source)
	at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(Unknown Source)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
	at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(Unknown Source)
	at com.sun.proxy.$Proxy21.register(Unknown Source)
	at com.xilen.Client.main(Client.java:19)
    2、客戶端

        (1)自定義Handler繼承SOAPHandler<T>

public class HeaderHandlerClient implements SOAPHandler<SOAPMessageContext> {

	@Override
	public boolean handleMessage(SOAPMessageContext context) {
		
		try {
			/**
			 * True表示Out False表示In
			 */
			Boolean messageTag = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
			
			/**
			 *如果是Out 
			 */
			if(messageTag){
				
				SOAPMessage message = context.getMessage();
				SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
				SOAPHeader header = envelope.getHeader();
				
				if(header == null){
					/**
					 * 通過envelope方式獲取hander,主要是為了能夠在Header為空的時候,通過envelope.addHeader()方法新增Header
					 */
					header = envelope.addHeader();
				}

				/**
				 * 新增Header資訊
				 */
				QName headerQName = new QName("http://impl.jws.xilen.com/", "info", "ns");
				header.addHeaderElement(headerQName).setValue("admin");
				
				/**
				 * 列印整個SOAP訊息
				 */
				message.writeTo(System.out);
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return true;
	}

	@Override
	public boolean handleFault(SOAPMessageContext context) {
		System.out.println("fault");
		return false;
	}

	@Override
	public void close(MessageContext context) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Set<QName> getHeaders() {
		// TODO Auto-generated method stub
		return null;
	}

}
        (2)編輯handler-chains配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	
	<javaee:handler-chain>
		<javaee:handler>
			<javaee:handler-class>com.xilen.HeaderHandlerClient</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
	
</javaee:handler-chains>

        (3)在服務上新增Handler

<pre name="code" class="java">/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.4-b01
 * Generated source version: 2.2
 * 
 * 在通過wsimport命令生成的服務實現類(繼承了Service)的類上新增@HandlerChain以配置客戶端Handler
 */
@WebServiceClient(name = "UserServiceImplService", targetNamespace = "http://impl.jws.xilen.com/", 
	wsdlLocation = "http://localhost:8888/userinfo?wsdl")
@HandlerChain(file="jax-handler.xml")
public class UserServiceImplService extends Service
{
    ……
}


        (4)再次測試Handler

/**
* 此時已經可以正確訪問服務並返回結果
*/
admin, registered!
四、一些補充

    如果需要針對某一些服務即操作才做驗證,可以在Handler中通過SoapBody獲取part以判斷當前服務

	@Override
	public boolean handleMessage(SOAPMessageContext context) {

		try {
			Boolean messageTag = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

			if(messageTag == false){
				
				SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
				
				/**
				 *  如果需要針對某一些操作才做驗證,可以通過SoapBody獲取part做判斷
				 */
				String partName = envelope.getBody().getChildNodes().item(0).getLocalName(); 
				
				if("list".equals(partName)){
					/**
					 *  驗證header的邏輯
					 */
					SOAPHeader header = envelope.getHeader();
					
					if(header == null || ! header.examineAllHeaderElements().hasNext()){
						
						SOAPFault fault = envelope.getBody().addFault();
						fault.setFaultString("驗證資訊為空!");
						
						throw new SOAPFaultException(fault);
						
					}else{
						
						Iterator<SOAPHeaderElement> iterator = header.extractAllHeaderElements();
						
						if(iterator.hasNext()){
							
							SOAPHeaderElement headerEle = iterator.next();
							
							System.out.println(headerEle.getTextContent());
							
						}
					}
				}
				
			}
		} catch (SOAPException e) {
			e.printStackTrace();
		}
		
		return true;
	}
五、資源下載

    http://download.csdn.net/detail/u013379717/7463923
 

 
 
 

相關文章