深入SOAP发送消息的过程(SAAJ)

本文介绍SOAP服务的搭建步骤及客户端如何发送SOAP请求。详细展示了服务端接口定义和服务实现,以及客户端创建SOAP消息和调用服务的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[b]
SOAP结构体
SOAPMessage
SOAPPart
SOAPEnvelope
SOAPHeader(optional)
SOAPBody(XML Content or SOAPFault)
AttachmentPart
MIME Headers
Content(XML or non-XML)
[/b]

[b]服务端[/b]
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;
}

}



[b]开启/运行服务[/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);
}
}



[b]向服务端发送SOAP消息[/b]
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 {

}
}
}



[b]运行结果[/b]
发送的数据:

<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;
}

}



[b]使用payload传递user对象[/b]
[color=blue]
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对象
[/color]

/**
* 模拟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 {

}
}


[b]通过Message传递List[/b]

/**
* 通过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 {

}
}


[b]结果:[/b]
[color=blue]
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]
[/color]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值