SOAP Handler

概述


SOAP Handler是一個SOAP message的攔截器,它能夠攔截進來或出去兩個方向的SOAP message,修改並決定是否放行。java

例如:

在服務端啓用一個handler,攔截請求的message,檢查是否包含指定的head參數;包含的放行,不包含的以異常做爲響應。在客戶端啓用一個handler,攔截髮出的請求message,向其中添加指定的head參數。
其實現以下文。

服務端


文件分佈圖

說明:這裏使用了Maven的結構,將java文件和xml文件分別放置在src/main/java和src/main/resources兩個源文件夾下。

Handler

建立一個handler攔截全部請求的message,嘗試從head中獲取用戶信息;獲取成功就放行,不然以拋出異常做爲響應。
handler須要實現javax.xml.ws.handler.soap.SOAPHandler接口。
AccessHandler.java
package cn.ljl.sand.jws.chapter4.service.handler;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPFaultException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class AccessHandler implements SOAPHandler<SOAPMessageContext> {
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean out = (Boolean) context
                .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        // true表示出的方向,即服務端返回的時候;false表示進的方向,即服務端接收請求參數的時候
        if (!out) {
            SOAPHeader header = null;
            
            try {
                header = context.getMessage().getSOAPPart().getEnvelope().getHeader();
            } catch (SOAPException e) {
                e.printStackTrace();
                return false;
            }
            if (header == null) {
                String tip = "缺乏頭部信息!";
                SOAPFaultException exception = createFaultException(tip);
                throw exception;
            } else if (!header.hasChildNodes()) {
                String tip = "頭部信息不能爲空!";
                SOAPFaultException exception = createFaultException(tip);
                throw exception;
            } else {
                NodeList nl = header.getElementsByTagNameNS(
                        "http://service.chapter4.jws.sand.ljl.cn/", "user");
                if (nl.getLength() == 0) {
                    String tip = "頭部信息中找不到用戶信息!";
                    SOAPFaultException exception = createFaultException(tip);
                    throw exception;
                }
                Node node = nl.item(0);
                String user = node.getTextContent();
                System.out.println("請求的用戶爲:" + user);
            }
        }
        return true;
    }
    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return false;
    }
    @Override
    public void close(MessageContext context) {
    }
    @Override
    public Set<QName> getHeaders() {
        return null;
    }
    /**
     * 根據消息建立異常.
     * 
     * @param message
     *            消息
     * @return
     */
    private SOAPFaultException createFaultException(String message) {
        SOAPFault fault = null;
        try {
            SOAPMessage smess = MessageFactory.newInstance().createMessage();
            SOAPBody body = smess.getSOAPPart().getEnvelope().getBody();
            fault = body.addFault();
            fault.setFaultString(message);
        } catch (SOAPException e) {
            e.printStackTrace();
            if (fault == null)
                return null;
        }
        SOAPFaultException exception = new SOAPFaultException(fault);
        return exception;
    }
}

Handler配置文件

Handler就是一個過濾器,配置文件能夠將多個Handler組裝成一個鏈,不一樣的配置文件能夠不一樣的方式組裝,如此就實現了代碼的重用和靈活的裝配。
Handler配置文件是一個xml文件。
handler-chains.xml
<?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>
                cn.ljl.sand.jws.chapter4.service.handler.AccessHandler
            </javaee:handler-class>
        </javaee:handler>
    </javaee:handler-chain>
</javaee:handler-chains>

服務接口

定義web服務的接口,不須要任何參數,返回一個字符串做爲成功的標誌;能被服務接收的請求都是成功的。
IAccessService.java
package cn.ljl.sand.jws.chapter4.service;
import javax.jws.WebResult;
import javax.jws.WebService;
@WebService
public interface IAccessService {
    @WebResult(name = "accessResult")
    public String access();
}

服務實現類

實現上面定義的接口,返回一個成功的字符串;使用@HandlerChain註解,指定Handler配置文件,此後請求該服務的消息將被配置文件中裝配的過濾鏈過濾。
AccessServiceImpl.java

 

package cn.ljl.sand.jws.chapter4.service;
import javax.jws.HandlerChain;
import javax.jws.WebService;
@WebService(endpointInterface = "cn.ljl.sand.jws.chapter4.service.IAccessService")
@HandlerChain(file = "cn/ljl/sand/jws/chapter4/service/handler/handler-chains.xml")
public class AccessServiceImpl implements IAccessService {
    @Override
    public String access() {
        String message = "你成功了!";
        return message;
    }
}

 

服務發佈者

定義一個類,發佈服務。
AccessServicePublisher.java
package cn.ljl.sand.jws.chapter4.service;
import javax.xml.ws.Endpoint;
public class AccessServicePublisher {
    public static void main(String[] args) {
        String address = "http://localhost:6666/service/access";
        IAccessService service = new AccessServiceImpl();
        Endpoint.publish(address, service);
    }
}

發佈服務

運行AccessServicePublisher的main,發佈服務,wsdl地址:http://localhost:6666/service/access?wsdl

客戶端


文件分佈圖

說明:src/main/java:cn.ljl.sand.jws.chapter4.client.wsimport中的文件,都是使用wsimport生成的,不作詳細介紹。

Handler

建立一個Handler,攔截全部發出的請求message,往其中添加head參數,而後放行。
UserHandler.java
package cn.ljl.sand.jws.chapter4.client.handler;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class UserHandler implements SOAPHandler<SOAPMessageContext> {
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean out = (Boolean) context
                .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        // true表示出的方向,即發送請求到服務端
        if (out) {
            try {
                SOAPEnvelope envelope = context.getMessage().getSOAPPart()
                        .getEnvelope();
                SOAPHeader header = envelope.getHeader();
                if (header == null)
                    header = envelope.addHeader();
                QName hname = new QName(
                        "http://service.chapter4.jws.sand.ljl.cn/", "user");
                header.addChildElement(hname).setTextContent("楊過");
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }
    @Override
    public boolean handleFault(SOAPMessageContext context) {
        SOAPFault fault = null;
        try {
            SOAPEnvelope envelope = context.getMessage().getSOAPPart()
                    .getEnvelope();
            fault = envelope.getBody().getFault();
        } catch (SOAPException e) {
            e.printStackTrace();
            return false;
        }
        System.out.println("在客戶端Handler中:" + fault.getFaultString());
        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;
    }
}

Handler配置文件

handler-chains.xmlnode

  • <?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>
                    cn.ljl.sand.jws.chapter4.client.handler.UserHandler
                </javaee:handler-class>
            </javaee:handler>
        </javaee:handler-chain>
    </javaee:handler-chains>

使用wsimport生成代碼

指定-p cn.ljl.sand.jws.chapter4.client.wsimport
修改生成AccessServiceImplService.java,爲類添加註解:
@HandlerChain(file = "cn/ljl/sand/jws/chapter4/client/handler/handler-chains.xml")

客戶端

建立一個測試類,發起請求。
WSIClient.java
package cn.ljl.sand.jws.chapter4.client;
import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Assert;
import org.junit.Test;
import cn.ljl.sand.jws.chapter4.client.wsimport.AccessServiceImplService;
import cn.ljl.sand.jws.chapter4.client.wsimport.IAccessService;
public class WSIClient {
    /** wsdl的地址 */
    private static final String WSDL_URL = "http://localhost:6666/service/access?wsdl";
    @Test
    public void test() throws MalformedURLException {
        URL url = new URL(WSDL_URL);
        AccessServiceImplService ss = new AccessServiceImplService(url);
        IAccessService service = ss.getAccessServiceImplPort();
        String message = service.access();
        Assert.assertEquals("你成功了!", message);
    }
}

測試


客戶端不添加head參數

AccessServiceImplService.java咱們添加的註解去掉,進行測試:

客戶端添加head參數

在AccessServiceImplService.java中添加 @HandlerChain註解 ,進行測試:
 



相關文章
相關標籤/搜索