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


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]

你可能感兴趣的:(SOAP)