webservice系统学习笔记5-手动构建/发送/解析SOAP消息
手动拼接SOAP消息调用webservice
SOAP消息的组成:
1、创建需要发送的SOAP消息的XML(add方法为例子)
/** * 创建访问add方法的SOAP消息的xml */ @Test public void test1(){ try { //1、创建消息工厂 MessageFactory factory = MessageFactory.newInstance(); //2、根据消息工厂创建SoapMessage SOAPMessage message = factory.createMessage(); //3、创建SOAPPart SOAPPart part = message.getSOAPPart(); //4、获取SOAPENvelope SOAPEnvelope envelope = part.getEnvelope(); //5、可以通过SoapEnvelope有效的获取相应的Body和Header等信息 SOAPBody body = envelope.getBody(); //6、根据Qname创建相应的节点(QName就是一个带有命名空间的) QName qname = new QName("http://ws01.yzl.com", "add","ns");//<ns:add xmlns:ns=http://ws01.yzl.com>这里指定ns是前缀,必须指定,随便定义即可,不定义这消息将无效 //如果使用以下方式进行设置,会见<>转换为<和> //body.addBodyElement(qname).setValue("<a>1</a><b>2</b>"); SOAPBodyElement ele = body.addBodyElement(qname); ele.addChildElement("a").setValue("22"); ele.addChildElement("b").setValue("33"); //打印消息信息 message.writeTo(System.out); } catch (Exception e) { e.printStackTrace(); } }
结果为下:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body><ns:add xmlns:ns="http://ws01.yzl.com"><a>22</a><b>33</b></ns:add> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
2、提交创建的SOAP消息的xml到服务器端与其进行通信
2.1、使用SOAPMessage和Service.Mode.MESSAGE的方式发送消息
/** * 发送add方法的SOAP的消息并接受解析返回的soap消息(使用Service.Mode.MESSAGE模式进行发送数据) <service name="MyServiceImplService"> <port name="MyServiceImplPort" binding="tns:MyServiceImplPortBinding"> <soap:address location="http://localhost:8888/ws01" /> </port> </service> * */ @Test public void test2(){ try { String namespace = "http://ws01.yzl.com/"; String wsdlUrl = "http://localhost:8888/ws01?wsdl"; //1、创建服务(Service) URL url = new URL(wsdlUrl); QName qname = new QName(namespace,"MyServiceImplService"); Service service = Service.create(url, qname); //2、创建Dispatch //public interface Dispatch<T>extends BindingProviderDispatch 接口提供对动态调用服务端点操作的支持。javax.xml.ws.Service 接口作为创建 Dispatch 实例的工厂。 Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(namespace,"MyServiceImplPort"), SOAPMessage.class, Service.Mode.MESSAGE); //3、创建SOAPMessage MessageFactory factory = MessageFactory.newInstance(); SOAPMessage message = factory.createMessage(); SOAPPart part = message.getSOAPPart(); SOAPEnvelope envelope = part.getEnvelope(); SOAPBody body = envelope.getBody(); QName portQname = new QName("http://ws01.yzl.com/", "add","ns"); SOAPBodyElement ele = body.addBodyElement(portQname); ele.addChildElement("a").setValue("22"); ele.addChildElement("b").setValue("33"); //4、通过Dispatch传递消息,并返回响应消息 SOAPMessage returnMessage = dispatch.invoke(message); returnMessage.writeTo(System.out);//打印返回消息 System.out.println(); //5、解析返回的SOAP消息的XML Document doc = returnMessage.getSOAPBody().extractContentAsDocument(); //Document doc = returnMessage.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(); String result = doc.getElementsByTagName("addResult").item(0).getTextContent(); System.out.println("result is :" + result); } catch (Exception e) { e.printStackTrace(); } }
结果:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header/> <S:Body> <ns2:addResponse xmlns:ns2="http://ws01.yzl.com/"><addResult>55</addResult></ns2:addResponse> </S:Body> </S:Envelope> result is :55
2.2、使用Source和Service.Mode.PAYLOAD的方式来发送消息
接口IMyService.java中添加方法:
/** *这里将WebResult和WebParam定义为user是为了使用jaxb进行类的编排和反编排时方便 */ @WebResult(name="user") public List<User> getChildListByUser(@WebParam(name="user")User user);
@Override public List<User> getChildListByUser(User user) { List<User> result = new ArrayList<User>(); result.add(new User("张三", "11111")); result.add(new User("李四", "22222")); return result; }
这时wsdl中的定义如下:
调用代码:
/** * 使用Source和Service.Mode.PAYLOAD的方式来发送消息 * 使用JAXB来对User对象进行编排和反编排 * 使用xpath解析xml * @throws Exception */ @Test public void test3() throws Exception{ String namespace = "http://ws01.yzl.com/"; String wsdlUrl = "http://localhost:8888/ws01?wsdl"; //1、创建服务(Service) URL url = new URL(wsdlUrl); QName qname = new QName(namespace,"MyServiceImplService"); Service service = Service.create(url, qname); //2、创建Dispatch(通过源数据的方式传递) Dispatch<Source> dispatch = service.createDispatch(new QName(namespace,"MyServiceImplPort"),Source.class, Service.Mode.PAYLOAD); //3、根据用户对象创建相应的xml(user对象的属性可以通过wsdl文件构建出来) User user = new User("管理员","123456"); JAXBContext jaxb = JAXBContext.newInstance(User.class); Marshaller ms = jaxb.createMarshaller(); ms.setProperty(Marshaller.JAXB_FRAGMENT, true);//去掉xml声明 StringWriter writer = new StringWriter(); ms.marshal(user, writer); //System.out.println(writer.toString());//<user><password>123456</password><username>管理员</username></user> //4、封装相应的part addUser String payload = "<nn:getChildListByUser xmlns:nn=\""+namespace+"\">"+writer.toString()+"</nn:getChildListByUser>"; System.out.println(payload); StreamSource rs = new StreamSource(new StringReader(payload)); //5、通过dispatch传递payload Source response = (Source)dispatch.invoke(rs); //6、将Source转化为DOM进行操作,使用Transform对象转换 Transformer tran = TransformerFactory.newInstance().newTransformer(); DOMResult result = new DOMResult(); tran.transform(response, result); //7、处理相应信息(通过xpath处理) XPath xpath = XPathFactory.newInstance().newXPath(); NodeList nl = (NodeList)xpath.evaluate("//user", result.getNode(),XPathConstants.NODESET); for(int i=0; i<nl.getLength(); i++){ User ru = (User)jaxb.createUnmarshaller().unmarshal(nl.item(i)); System.out.println(ru.getUsername()); } }
结果如下:
<nn:getChildListByUser xmlns:nn="http://ws01.yzl.com/"><user><password>123456</password><username>管理员</username></user></nn:getChildListByUser> 张三 李四