SOAP Handler

概述


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();
}

服务实现类

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





原文地址:https://www.cnblogs.com/ywjy/p/5196085.html