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