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> {@Overridepublic Set<QName> getHeaders() {return null;}@Overridepublic void close(MessageContext context) {}@Overridepublic boolean handleFault(SOAPMessageContext context) {System.out.println("error");return false;}@Overridepublic 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> {@Overridepublic Set<QName> getHeaders() {return null;}@Overridepublic void close(MessageContext context) {}@Overridepublic boolean handleFault(SOAPMessageContext context) {return false;}@Overridepublic 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
头部信息不能为空!
?