SOAP结构体
SOAPMessage
SOAPPart
SOAPEnvelope
SOAPHeader(optional)
SOAPBody(XML Content or SOAPFault)
AttachmentPart
MIME Headers
Content(XML or non-XML)
服务端
IMyService.java
package com.hqh.soap;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
@WebService
public interface IMyService {
@WebResult(name="addResult")
public int add(@WebParam(name="a")int a,@WebParam(name="b")int b);
}
MyServiceImpl.java
package com.hqh.soap;
import javax.jws.WebService;
@WebService(endpointInterface="com.hqh.soap.IMyService")
public class MyServiceImpl implements IMyService {
@Override
public int add(int a, int b) {
System.out.println("MyServiceImpl.add()");
return a+b;
}
}
开启/运行服务
MyServer.java
package com.hqh.soap;
import javax.xml.ws.Endpoint;
public class MyServer {
public static void main(String[] args) {
String address = "http://localhost:8888/ms";
IMyService implementor = new MyServiceImpl();
Endpoint.publish(address, implementor);
}
}
向服务端发送SOAP消息
TestSOAP.java
package com.hqh.soap;
import java.io.IOException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import org.junit.Test;
import org.w3c.dom.Document;
public class TestSOAP {
/**
* 演示SOAP消息的创建过程
*/
@Test
public void test01() {
//1.创建消息工厂
try {
MessageFactory factory = MessageFactory.newInstance();
//2.使用factory创建SoapMessage
SOAPMessage message = factory.createMessage();
//创建soapPart
SOAPPart part = message.getSOAPPart();
//获取soapEnvelope信封
SOAPEnvelope envelope = part.getEnvelope();
//通过信封就可以获取head和body的相关信息
SOAPBody body = envelope.getBody();
//根据QName创建相应节点【QName就是一个带有命名空间的节点】
String namespaceURI = "http://webservice/example/soap";
String localPart = "add";
String prefix = "ns";
QName qName = new QName(namespaceURI, localPart, prefix);
//<ns:add xmlns="http://webservice/example/soap"/>
SOAPBodyElement bodyEle = body.addBodyElement(qName);
bodyEle.addChildElement("a").setValue("1");
bodyEle.addChildElement("b").setValue("9");
//body.addBodyElement(qName).setValue("<a>1</a> <b>2</b>");
//打印消息
message.writeTo(System.out);
} catch (SOAPException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 模拟SOAP发送消息,接收返回值的过程
*/
@Test
public void test02() {
try {
//1.创建服务
URL wsdlDocumentLocation = new URL("http://localhost:8888/ms?wsdl");
String ns = "http://soap.hqh.com/";//wsdl的命名空间
String localPart = "MyServiceImplService";//服务的名称
QName serviceName = new QName(ns,localPart);
Service service = Service.create(wsdlDocumentLocation, serviceName);
//2.创建Dispatch
QName portName = new QName(ns,"MyServiceImplPort");
Dispatch<SOAPMessage> dispatch =
service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
//3.创建SOAPMessage
SOAPMessage message = MessageFactory.newInstance().createMessage();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
//4.通过QName指定消息中需要传递的数据
String prefix = "nn";//前缀必须指定,任意
String invokeMethodName = "add";//指定服务端被调用的方法
QName ename = new QName(ns, invokeMethodName, prefix);
SOAPBodyElement bodyElement = body.addBodyElement(ename);
bodyElement.addChildElement("a").setValue("12");
bodyElement.addChildElement("b").setValue("32");
message.writeTo(System.out);
System.out.println("invoking...");
//5.传递消息
SOAPMessage retMessage = dispatch.invoke(message);
retMessage.writeTo(System.out);
System.out.println();
//将相应的消息转换为dom对象
Document doc = retMessage.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
String retValue = doc.getElementsByTagName("addResult").item(0).getTextContent();
System.out.println("retValue="+retValue);
} catch(Exception e) {
e.printStackTrace();
} finally {
}
}
}
运行结果
发送的数据:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<nn:add xmlns:nn="http://soap.hqh.com/">
<a>12</a>
<b>32</b>
</nn:add>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
接收的数据:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header />
<S:Body>
<ns2:addResponse xmlns:ns2="http://soap.hqh.com/">
<addResult>44</addResult>
</ns2:addResponse>
</S:Body>
</S:Envelope>
package com.hqh.soap;
import java.util.List;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
@WebService
public interface IMyService {
@WebResult(name="addResult")
public int add(@WebParam(name="a")int a,@WebParam(name="b")int b);
@WebResult(name="user")
public User addUser(@WebParam(name="user")User user);
@WebResult(name="user")
public User login(@WebParam(name="username")String username,@WebParam(name="pwd")String pwd);
@WebResult(name="user")
public List<User> list();
}
package com.hqh.soap;
import java.util.ArrayList;
import java.util.List;
import javax.jws.WebService;
@WebService(endpointInterface="com.hqh.soap.IMyService")
public class MyServiceImpl implements IMyService {
private static List<User> users = new ArrayList<User>();
public MyServiceImpl() {
users.add(new User(1,"admin","admin"));
}
@Override
public int add(int a, int b) {
System.out.println("MyServiceImpl.add()");
return a+b;
}
@Override
public User addUser(User user) {
users.add(user);
return user;
}
@Override
public User login(String username, String pwd) {
for(User user:users) {
if(username.equals(user.getName()) && pwd.equals(user.getPwd()))
return user;
}
return null;
}
@Override
public List<User> list() {
return users;
}
}
使用payload传递user对象
1.创建对象并使用JAXB将其转换为xml格式
2.组装part节点
3.将part节点转换为Source源
4.通过dispatcher发送数据并接收返回的Source
5.将返回的Source转换为DomResult
6.通过DomResult获取Node
7.通过xpath从node获取NodeList
8.再通过JAXB的unmarshaller将node转换为User对象
/**
* 模拟SOAP发送消息,接收返回值的过程
* 使用payload方式传输,不是以message的方式传递,而是以字符串的形式完成数据传输
*/
@Test
public void test03() {
try {
//1.创建服务
URL wsdlDocumentLocation = new URL("http://localhost:8888/ms?wsdl");
String ns = "http://soap.hqh.com/";//wsdl的命名空间
String localPart = "MyServiceImplService";//服务的名称
QName serviceName = new QName(ns,localPart);
Service service = Service.create(wsdlDocumentLocation, serviceName);
//2.创建Dispatch
QName portName = new QName(ns,"MyServiceImplPort");
//通过元数据的方式传递
Dispatch<Source> dispatch =
service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
//3.使用JAXB将对象转换为xml
User jaxbElement = new User(100,"root","root");
JAXBContext ctx = JAXBContext.newInstance(User.class);
Marshaller marshaller = ctx.createMarshaller();
//不要生成xml头:<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
Writer writer = new StringWriter();
//将转换后的xml写入到字符输出流中
marshaller.marshal(jaxbElement, writer);
System.out.println(writer);
//转换后的结果:<user><id>100</id><name>root</name><pwd>root</pwd></user>
//4.封装Part
String payload = "<nn:addUser xmlns:nn=\""+ns+"\">"+writer+"</nn:addUser>";
System.out.println(payload);
//<nn:addUser xmlns:nn="http://soap.hqh.com/"><user><id>100</id><name>root</name><pwd>root</pwd></user></nn:addUser>
//5.通过dispatcher传递source
//将字符串转换为Source类型
Source reqSource = new StreamSource(new StringReader(payload));
//发送数据并得到返回的Source
Source respSource = dispatch.invoke(reqSource);
//6.转换返回的Source为DomSource
DOMResult domResult = new DOMResult();
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.transform(respSource, domResult);
//7.处理转换后的DomResult获取结果
Node node = domResult.getNode();
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xpath.evaluate("//user", node, XPathConstants.NODESET);
//反编排,将Node转换为对象
User user = (User)ctx.createUnmarshaller().unmarshal(nodeList.item(0));
System.out.println(user);
//结果:User [id=100, name=root, pwd=root]
} catch(Exception e) {
e.printStackTrace();
} finally {
}
}
通过Message传递List
/**
* 通过Message传递List
*/
@Test
public void test04() {
try {
//1.创建服务
URL wsdlDocumentLocation = new URL("http://localhost:8888/ms?wsdl");
String ns = "http://soap.hqh.com/";//wsdl的命名空间
String localPart = "MyServiceImplService";//服务的名称
QName serviceName = new QName(ns,localPart);
Service service = Service.create(wsdlDocumentLocation, serviceName);
//2.创建Dispatch
QName portName = new QName(ns,"MyServiceImplPort");
Dispatch<SOAPMessage> dispatch =
service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
//3.创建SOAPMessage
SOAPMessage message = MessageFactory.newInstance().createMessage();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
//4.通过QName指定消息中需要传递的数据
String prefix = "nn";//前缀必须指定,任意
// String invokeMethodName = "add";//指定服务端被调用的方法
String invokeMethodName = "list";//指定服务端被调用的方法
QName ename = new QName(ns, invokeMethodName, prefix);
SOAPBodyElement bodyElement = body.addBodyElement(ename);
// bodyElement.addChildElement("a").setValue("12");
// bodyElement.addChildElement("b").setValue("32");
message.writeTo(System.out);
System.out.println("\n invoking...");
//5.传递消息
SOAPMessage retMessage = dispatch.invoke(message);
retMessage.writeTo(System.out);
System.out.println();
//将相应的消息转换为dom对象
Document doc = retMessage.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
// String retValue = doc.getElementsByTagName("addResult").item(0).getTextContent();
// System.out.println("retValue="+retValue);
//通过dom获取node;通过node转换为对象
JAXBContext ctx = JAXBContext.newInstance(User.class);
List<User> userList = new ArrayList<User>();
NodeList nodeList = doc.getElementsByTagName("user");
for(int i=0;i<nodeList.getLength();i++) {
Node node = nodeList.item(i);
User u = (User)ctx.createUnmarshaller().unmarshal(node);
userList.add(u);
}
for(User u : userList) {
System.out.println(u);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
}
}
结果:
list中user对象的个数与执行test03相关(addUser)。
User [id=1, name=admin, pwd=admin]
User [id=100, name=root, pwd=root]
User [id=100, name=root, pwd=root]