IT源码网

SOAP Handler讲解

lxf 2021年06月07日 程序员 117 0

概述


SOAP Handler是一个SOAP message的拦截器,它可以拦截进来或出去两个方向的SOAP message,修改并决定是否放行。

例如:

在服务端启用一个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(); 
}

服务实现类

实现上面定义的接口,返回一个成功的字符串;[email protected],指定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.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.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注解 ,进行测试:
 






发布评论

分享到:

IT源码网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

基于wsimport生成代码的客户端讲解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。