soap中Handler的处置
通过java提供的wsimport命令把wsdl导成.java或.class,如下图:
生成文件如下图:
接着创建独立的java项目,把这些java文件拷贝到src下面,再次创建客户MyClient.java
package com.webservice; public class MyClient { public static void main(String[] args) { MyServiceImplService msis = new MyServiceImplService(); IMyService ms = msis.getMyServiceImplPort(); try { ms.login("admin", "11111"); } catch (UserException_Exception e) { System.out.println(e.getMessage()); } } }
运行结果:
用户名或密码不正确!
现在想这样一个问题:服务器已经把某个方法发布了(不能再更改了),这个时候,有这样一个需求,在客户端调用服务端方法传递数据信息的时候,需要传递一些其他的信息(比如:头信息),这时在客户端貌似没法处理这样的需求了,那么,针对于这样的需求,引出一个新的知识点:handler,它有两种类型:LogicHandler和SOAPHandler,前者只能获取SOAPBody的信息,后者可以获取SOAPMessage的信息。用的比较多的是SOAPHandler
创建一个handler类(实现SOAPHandler接口)
HeaderHandler.java
package com.webservice.handler; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; 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 HeaderHandler implements SOAPHandler<SOAPMessageContext> { @Override public Set<QName> getHeaders() { return null; } @Override public void close(MessageContext context) { } @Override public boolean handleFault(SOAPMessageContext context) { System.out.println("error"); return false; } @Override public boolean handleMessage(SOAPMessageContext context) { try { boolean out = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (out) {// 客户端这里是发送消息,因此在out的时候发送 SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope(); SOAPHeader header = envelope.getHeader(); if (header == null) { header = envelope.addHeader(); } QName qname = new QName("http://www.webservice.com", "licenseInfo", "ns"); header.addHeaderElement(qname).setValue("12345"); } } catch (SOAPException e) { e.printStackTrace(); } return true; } }
handleFault方法是处理异常错误的。
在classpath目录下,创建handler的配置文件
handler-chain.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <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.webservice.handler.HeaderHandler </javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>
修改生成的MyServiceImplService.java文件,在此类类名上添加注解:@HandlerChain(file = "handler-chain.xml")
(1)为了清楚地查看客户端的信息发送服务端的时候信息中包含头信息,修改MyClient.java
package com.webservice; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.soap.SOAPFaultException; public class MyClient { public static void main(String[] args) throws MalformedURLException { // MyServiceImplService msis = new MyServiceImplService(); URL url = new URL("http://localhost:6666/server?wsdl"); QName qName = new QName("http://www.webservice.com", "MyServiceImplService"); MyServiceImplService msis = new MyServiceImplService(url, qName); IMyService ms = msis.getMyServiceImplPort(); try { ms.login("admin", "11111"); } catch (UserException_Exception e) { System.out.println(e.getMessage()); } catch (SOAPFaultException e) { System.out.println(e.getMessage()); } } }
然后,使用eclipse的TCP/IP Monitor工具进行捕获,如下图:
其中,6666端口为监听端口(和客户端代码设置的端口一致),9999端口为发布的服务端端口,类型选择TCP/IP,点击ok后,点击start启动6666监听端口,再次运行MyClient.java,运行结果:
error
用户名或密码不正确!
而在TCP/IP Monitor工具窗口中,很清楚地捕获到了发往服务端的信息中,包含头信息,如下图:
(2)为了清楚地查看服务端接收的信息中包含客户端发过来的头信息,在服务端创建一个handler类(实现SOAPHandler接口)
LicenseHandler.java(这里只针对login和addUser方法做头信息的处理,传递过来的信息可能有头信息,也可能没有头信息,如果没有,做相应的异常处理)
package com.test.handler; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPBody; 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; import javax.xml.ws.soap.SOAPFaultException; import org.w3c.dom.NodeList; public class LicenseHandler implements SOAPHandler<SOAPMessageContext> { @Override public Set<QName> getHeaders() { return null; } @Override public void close(MessageContext context) { } @Override public boolean handleFault(SOAPMessageContext context) { return false; } @Override public boolean handleMessage(SOAPMessageContext context) { try { boolean out = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (!out) {// 服务端这里是获取消息,因此在in的时候获取 SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope(); SOAPHeader header = envelope.getHeader(); SOAPBody body = envelope.getBody(); String localName = body.getChildNodes().item(0).getLocalName(); if ("login".equals(localName) || "addUser".equals(localName)) { if (header.hasChildNodes()) { NodeList nl = (NodeList) header.getElementsByTagName("ns:licenseInfo"); System.out.println(nl.item(0).getTextContent()); } else { SOAPFault fault = body.addFault(); fault.setFaultString("头部信息不能为空!"); throw new SOAPFaultException(fault); } } } } catch (SOAPException e) { e.printStackTrace(); } return true; } }
在classpath目录下,创建handler的配置文件
handler-chain.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <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.test.handler.LicenseHandler</javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>
修改服务端MyServiceImpl.java文件,在此类类名上添加注解:@HandlerChain(file = "handler-chain.xml")
再次运行客户端MyClient.java
客户端运行结果:
error
用户名或密码不正确!
服务端运行结果:
12345
【运行结果说明服务端成功获取到了客户端发来的头信息。】
如果客户端发信息的时候不携带头信息,也就是说清空HeaderHandler.java中的handleMessage方法
再次运行客户端MyClient.java
客户端运行结果:
error
头部信息不能为空!