通过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
头部信息不能为空!