加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

【JAX-WS入门系列】第03章_使用SAAJ创建SOAP消息

发布时间:2020-12-17 00:24:01 所属栏目:安全 来源:网络整理
导读:这是一个Java Project,先放服务端代码 首先是SEI,即服务端接口类HelloService.java package com.jadyer.service;import java.util.List;import javax.jws.WebParam;import javax.jws.WebResult;import javax.jws.WebService;import com.jadyer.model.User;

这是一个Java Project,先放服务端代码


首先是SEI,即服务端接口类HelloService.java

package com.jadyer.service;

import java.util.List;

import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

import com.jadyer.model.User;

@WebService
public interface HelloService {
	@WebResult(name="loginResult")
	public String login(@WebParam(name="username")String username,@WebParam(name="password")String password);
	
	//这里之所以把返回值和参数名都定义为user
	//是为了生成的soap请求消息和响应消息都是<user><id>...</id></user>样子的有规律的xml
	//这样我们就可以很方便的使用JAXB来把消息转成JavaBean
	@WebResult(name="user")
	public User addUser(@WebParam(name="user")User user);
	
	@WebResult(name="user")
	public List<User> list();
}

然后是SIB,即服务端接口实现类HelloServiceImpl.java

package com.jadyer.service;

import java.util.ArrayList;
import java.util.List;

import javax.jws.WebService;

import com.jadyer.model.User;

@WebService(endpointInterface="com.jadyer.service.HelloService")
public class HelloServiceImpl implements HelloService {
	//模拟一个位于内存中的小仓库
	private static List<User> users = new ArrayList<User>();
	
	//初始化一个用户
	public HelloServiceImpl(){
		users.add(new User(1,"admin","管理员","222222"));
	}
	
	@Override
	public String login(String username,String password) {
		System.out.println("login() is invoked......");
		for(User user : users){
			if(user.getUsername().equals(username) && user.getPassword().equals(password)){
				return "用户[" + username + "]登录成功";
			}
		}
		return "用户[" + username + "]登录失败";
	}
	
	@Override
	public User addUser(User user) {
		System.out.println("addUser() is invoked......");
		users.add(user);
		return user;
	}

	@Override
	public List<User> list() {
		System.out.println("list() is invoked......");
		return users;
	}
}

下面是服务端用到的映射XML的实体类User.java

package com.jadyer.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {
	private int id;
	private String username;
	private String nickname;
	private String password;
	
	/*四个属性的setter和getter略*/
	
	public User() {}

	public User(int id,String username,String nickname,String password) {
		this.id = id;
		this.username = username;
		this.nickname = nickname;
		this.password = password;
	}
}

最后是用于发布服务的MainApp.java

package com.jadyer.server;

import javax.xml.ws.Endpoint;

import com.jadyer.service.HelloServiceImpl;

public class MainApp {
	public static void main(String[] args) {
		Endpoint.publish("http://127.0.0.1:8888/myHelloService",new HelloServiceImpl());
	}
}

至此,WebServices服务端发布完毕。


下面是借助SAAJ编写客户端的演示

package com.jadyer.client;

import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
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.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.jadyer.model.User;

/**
 * 借助SAAJ创建SOAP消息并访问服务
 * @see SAAJ(SOAP with Attachments API for Java)是JAXM(Java API for XML Messaging)的一个分支
 * @see ----------------------------------------------------------------------------------------------
 * @see Web服务的基础是以标准格式发送和接收消息,这种标准格式是SOAP
 * @see 使用SAAJ可以手工生成SOAP消息,并发送给服务端,同样可以接收服务端响应
 * @see ----------------------------------------------------------------------------------------------
 * @see 这里推荐一个WebServices必用的一个免费工具soapUI(http://www.soapui.org/)
 * @see 通过它new一个soapUI Project后,我们可以清晰的看到需要发送的SOAP消息和响应的SOAP消息格式
 * @see 这对于理解本文,有莫大的帮助..类似的还有Apache的TCPMon(http://ws.apache.org/commons/tcpmon/)
 * @see ----------------------------------------------------------------------------------------------
 * @create Mar 18,2013 2:47:18 PM
 * @author 玄玉<http://blog.csdn/net/jadyer>
 */
public class TestSAAJ {
	//Web服务端公布的服务地址
	private static String wsdlURL = "http://127.0.0.1:8888/myHelloService?wsdl";
	//取自WSDL文件顶部的<definitions targetNamespace="">的值
	private static String nameSpace = "http://service.jadyer.com/";
	
	/**
	 * 以MESSAGE方式与Web服务交互SOAP消息
	 * @see 这里请求的是Web服务端login()方法
	 * @see ---------------------------------------------------------------------------------
	 * @see 下面是请求的SOAP消息
	 * @see <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
	 * @see 	<SOAP-ENV:Header />
	 * @see 	<SOAP-ENV:Body>
	 * @see 		<nn:login xmlns:nn="http://service.jadyer.com/">
	 * @see 			<username>admin</username>
	 * @see 			<password>222222</password>
	 * @see 		</nn:login>
	 * @see 	</SOAP-ENV:Body>
	 * @see </SOAP-ENV:Envelope>
	 * @see ---------------------------------------------------------------------------------
	 * @see 下面是响应的SOAP消息
	 * @see <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
	 * @see 	<S:Header />
	 * @see 	<S:Body>
	 * @see 		<ns2:loginResponse xmlns:ns2="http://service.jadyer.com/">
	 * @see 			<loginResult>用户[admin]登录成功</loginResult>
	 * @see 		</ns2:loginResponse>
	 * @see 	</S:Body>
	 * @see </S:Envelope>
	 * @see ---------------------------------------------------------------------------------
	 */
	private static void sendRequesetBySOAPMessage() throws Exception{
		/**
		 * 获取SOAPBody
		 */
		//通过消息工厂创建SoapMessage
		SOAPMessage message = MessageFactory.newInstance().createMessage();
		//创建SOAPPart
		SOAPPart part = message.getSOAPPart();
		//获取SOAPEnvelope(即信封)
		SOAPEnvelope envelope = part.getEnvelope();
		//通过SOAPEnvelope获取相应的Body和Header
		//这里不建议使用SOAPMessage.getSOAPHeader()或者SOAPMessage.getSOAPBody()获取Header和Body
		//因为SOAPMessage并没有提供addHeader()或者addBody()方法,不便于我们手工添加Header等等
		SOAPBody body = envelope.getBody();
		/**
		 * 构造SOAPMessage
		 */
		//根据QName创建相应的节点
		//这里的QName就是一个带有命名空间的节点,需要的三个参数分别'命名空间'--'请求Web服务的方法名'--'自定义的前缀'
		//那么,在这里它会创建出--><nn:login xmlns:nn="http://service.jadyer.com/">
		QName qname = new QName(nameSpace,"login","nn");
		//下面指定消息所传递的数据
		//如果直接这么写-->body.addBodyElement(qname).setValue("<a>11</a><b>22</b>");
		//那么发出去的<>会被转换为<和>,显然这不是我们所期望的,所以要使用addChildElement()
		SOAPBodyElement sbe = body.addBodyElement(qname);
		//这里输入的"username"就是Web服务端定义的login()方法的参数名称
		sbe.addChildElement("username").setValue("admin");
		sbe.addChildElement("password").setValue("222222");
		//打印请求消息到控制台
		message.writeTo(System.out);
		/**
		 * 通过Dispatch传递SOAPMessage
		 */
		//创建服务(这里QName的两个参数分别为WSDL文件顶部的<definitions targetNamespace="" name="">的值)
		//其中name属性值为公开的Web服务的接口实现类加上"Service",也是我们这里要传递的new QName()第二个参数
		Service service = Service.create(new URL(wsdlURL),new QName(nameSpace,"HelloServiceImplService"));
		//创建Dispatch
		//第一个参数:WSDL中<servcie><port name="">的name值,即HelloServiceImplPort,注意指明的命名空间,否则它不认识
		//第二个参数:指明存放数据的类型,我们这里是SOAPMessage.class
		//第三个参数:指明用户使用完整的协议消息还是消息负载,当类型为SOAPMessage时,模式必须为MESSAGE
		//其实第三个参数MESSAGE指的就是要把消息格式化成XML再进行传递,还有一种传递类型是PAYLOAD
		//PAYLOAD指的是通过负载的方式进行传递,换言之,是对一种编好码的数据进行传递,它会自动对字符串进行编码
		//所以PAYLOAD适用于自己组装字符串作为请求消息进行传递
		Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(nameSpace,"HelloServiceImplPort"),SOAPMessage.class,Service.Mode.MESSAGE);
		//通过Dispatch.invoke(SOAPMessage)方法发送请求消息,其返回值为Web服务端响应的消息
		SOAPMessage respMsg = dispatch.invoke(message);
		System.out.println("n发起请求:invoking......");
		//打印响应消息到控制台
		respMsg.writeTo(System.out);
		/**
		 * 转换响应消息为DOM对象
		 */
		Document doc = respMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
		//这里输入的"loginResult"就是Web服务端定义的login()方法的返回值名称
		System.out.println("n收到响应:" + doc.getElementsByTagName("loginResult").item(0).getTextContent());
	}
	
	
	/**
	 * 以MESSAGE方式与Web服务交互SOAP消息
	 * @see 这里请求的是Web服务端list()方法
	 */
	private static void sendRequesetBySOAPMessageForList() throws Exception{
		SOAPMessage message = MessageFactory.newInstance().createMessage();
		SOAPBody body = message.getSOAPPart().getEnvelope().getBody();
		body.addBodyElement(new QName(nameSpace,"list","nn")); //list()方法无参就不需要addChildElement了
		message.writeTo(System.out); //打印请求消息到控制台
		Service service = Service.create(new URL(wsdlURL),"HelloServiceImplService"));
		Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(nameSpace,Service.Mode.MESSAGE);
		SOAPMessage respMsg = dispatch.invoke(message);
		System.out.println("");
		respMsg.writeTo(System.out); //打印响应消息到控制台
		Document doc = respMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
		NodeList nodes = doc.getElementsByTagName("user");
		for(int i=0; i<nodes.getLength(); i++){
			Node node = nodes.item(i);
			/**
			 * JAXB反编排(直接让它来处理org.w3c.dom.Node)
			 */
			Unmarshaller unMarshaller = JAXBContext.newInstance(User.class).createUnmarshaller();
			User respUser = (User)unMarshaller.unmarshal(node);
			System.out.println("n收到响应:" + respUser.getUsername());
			System.out.println("收到响应:" + respUser.getNickname());
			System.out.println("收到响应:" + respUser.getPassword());
		}
	}
	
	
	/**
	 * 以PAYLOAD方式与Web服务交互SOAP消息
	 * @see 这里请求的是Web服务端addUser()方法
	 */
	private static void sendRequesetByPAYLOAD() throws Exception{
		/**
		 * JAXB编排
		 */
		User user = new User(3,"hongyu","洪雨","888888");
		Marshaller marshaller = JAXBContext.newInstance(User.class).createMarshaller();
		//该值默认为false,true则不会创建即头信息,即<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
		marshaller.setProperty(Marshaller.JAXB_FRAGMENT,true);
		StringWriter writer = new StringWriter();
		marshaller.marshal(user,writer);
		/**
		 * 拼装addUser()方法的SOAP消息的Body内容,即<nn:addUser xmlns="......"/>
		 */
		String payLoad = "<nn:addUser xmlns:nn="" + nameSpace + "">" + writer.toString() + "</nn:addUser>";
		System.out.println("拼装完毕:" + payLoad);
		/**
		 * 通过Dispatch传递payLoad
		 */
		Service service = Service.create(new URL(wsdlURL),"HelloServiceImplService"));
		Dispatch<Source> dispatch = service.createDispatch(new QName(nameSpace,Source.class,Service.Mode.PAYLOAD);
		Source response = dispatch.invoke(new StreamSource(new StringReader(payLoad)));
		/**
		 * 处理响应信息(利用Transformer对象将响应的Source转换为DOM)
		 */
		DOMResult domResult = new DOMResult();
		TransformerFactory.newInstance().newTransformer().transform(response,domResult);
		XPath xpath = XPathFactory.newInstance().newXPath();
		NodeList nodes = (NodeList)xpath.evaluate("//user",domResult.getNode(),XPathConstants.NODESET);
		/**
		 * JAXB反编排(直接让它来处理org.w3c.dom.Node)
		 */
		Unmarshaller unMarshaller = JAXBContext.newInstance(User.class).createUnmarshaller();
		User respUser = (User)unMarshaller.unmarshal(nodes.item(0));
		System.out.println("收到响应:" + respUser.getUsername());
		System.out.println("收到响应:" + respUser.getNickname());
		System.out.println("收到响应:" + respUser.getPassword());
	}
	
	
	/**
	 * SAAJ测试
	 */
	public static void main(String[] args) throws Exception {
		sendRequesetBySOAPMessage();
		System.out.println("---------------------------------------------------------------------------");
		sendRequesetByPAYLOAD();
		System.out.println("---------------------------------------------------------------------------");
		sendRequesetBySOAPMessageForList();
	}
}

最后列出的分别是WebServices服务端和客户端的控制台输出

2013-3-28 23:00:13 com.sun.xml.internal.ws.model.RuntimeModeler getRequestWrapperClass
信息: Dynamically creating request wrapper Class com.jadyer.service.jaxws.List
2013-3-28 23:00:13 com.sun.xml.internal.ws.model.RuntimeModeler getResponseWrapperClass
信息: Dynamically creating response wrapper bean Class com.jadyer.service.jaxws.ListResponse
2013-3-28 23:00:13 com.sun.xml.internal.ws.model.RuntimeModeler getRequestWrapperClass
信息: Dynamically creating request wrapper Class com.jadyer.service.jaxws.Login
2013-3-28 23:00:13 com.sun.xml.internal.ws.model.RuntimeModeler getResponseWrapperClass
信息: Dynamically creating response wrapper bean Class com.jadyer.service.jaxws.LoginResponse
2013-3-28 23:00:13 com.sun.xml.internal.ws.model.RuntimeModeler getRequestWrapperClass
信息: Dynamically creating request wrapper Class com.jadyer.service.jaxws.AddUser
2013-3-28 23:00:13 com.sun.xml.internal.ws.model.RuntimeModeler getResponseWrapperClass
信息: Dynamically creating response wrapper bean Class com.jadyer.service.jaxws.AddUserResponse
login() is invoked......
addUser() is invoked......
list() is invoked......
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><nn:login xmlns:nn="http://service.jadyer.com/"><username>admin</username><password>222222</password></nn:login></SOAP-ENV:Body></SOAP-ENV:Envelope>
发起请求:invoking......
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header/><S:Body><ns2:loginResponse xmlns:ns2="http://service.jadyer.com/"><loginResult>用户[admin]登录成功</loginResult></ns2:loginResponse></S:Body></S:Envelope>
收到响应:用户[admin]登录成功
---------------------------------------------------------------------------
拼装完毕:<nn:addUser xmlns:nn="http://service.jadyer.com/"><user><id>3</id><nickname>洪雨</nickname><password>888888</password><username>hongyu</username></user></nn:addUser>
收到响应:hongyu
收到响应:洪雨
收到响应:888888
---------------------------------------------------------------------------
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><nn:list xmlns:nn="http://service.jadyer.com/"/></SOAP-ENV:Body></SOAP-ENV:Envelope>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header/><S:Body><ns2:listResponse xmlns:ns2="http://service.jadyer.com/"><user><id>1</id><nickname>管理员</nickname><password>222222</password><username>admin</username></user><user><id>3</id><nickname>洪雨</nickname><password>888888</password><username>hongyu</username></user></ns2:listResponse></S:Body></S:Envelope>
收到响应:admin
收到响应:管理员
收到响应:222222

收到响应:hongyu
收到响应:洪雨
收到响应:888888

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读