1, SOAPMessage结构图
2, SOAP消息的创建
1>前面的一个简单WebService 服务
package com.yangw.soap.service; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; //说明该接口是服务接口,可以指定我们自己的命名空间 @WebServicepublic interface IMyService { /** * 使用注解指明返回值名,参数名 */ @WebResult(name="addResult") public int add(@WebParam(name="a")int a,@WebParam(name="b")int b); }
package com.yangw.soap.service; import javax.jws.WebService; //说明该类是服务接口的实现类 @WebService(endpointInterface="com.yangw.soap.service.IMyService") public class MyServiceImpl implements IMyService { @Override public int add(int a, int b) { System.out.println("a+b="+(a+b)); return a+b; } }
package com.yangw.soap.service; import javax.xml.ws.Endpoint; public class MyService { /** * @param args */ public static void main(String[] args) { //发布服务 Endpoint.publish("http://localhost:8899/ns", new MyServiceImpl()); } }
2>SOAPMessage的创建
package com.yangw.soap.test; import java.io.IOException; 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 org.junit.Test; public class TestSoap { /** * 自己创建soap协议 */ @Test public void test() { try { //1,创建消息工厂 MessageFactory factory=MessageFactory.newInstance(); //2,根据消息工厂创建soap消息 SOAPMessage msg=factory.createMessage(); //3,创建SOAPPart SOAPPart part=msg.getSOAPPart(); //4,获取soapEnvelope SOAPEnvelope envelope=part.getEnvelope(); //5,通过SOAPEnvelope可以有效的获取相应的Header和Body等 SOAPBody body=envelope.getBody(); //6,根据QName创建相应的节点(QName就是一个带有命名空间的节点) QName qName=new QName("http://service.soap.yangw.com/", "add", "ns"); //相当于<ns:add xmlns="http://service.soap.yangw.com/" /> //7,将QName加入到body中 // body.addBodyElement(qName).setValue("123123"); /** * <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> * <SOAP-ENV:Header/> * <SOAP-ENV:Body> * <ns:add xmlns:ns="http://service.soap.yangw.com/">123123</ns:add> * </SOAP-ENV:Body> * </SOAP-ENV:Envelope> */ //如果使用下面注释住的这个方式,会将<>转换为<> //body.addBodyElement(qName).setValue("<a>11</a><b>22</b>"); //加子元素 SOAPBodyElement bodyEle=body.addBodyElement(qName); bodyEle.addChildElement("a").setValue("11"); bodyEle.addChildElement("b").setValue("22"); //打印消息 msg.writeTo(System.out); /** * <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> * <SOAP-ENV:Header/> * <SOAP-ENV:Body> * <ns:add xmlns:ns="http://service.soap.yangw.com/"> * <a>11</a> * <b>22</b> * </ns:add> * </SOAP-ENV:Body> * </SOAP-ENV:Envelope> */ } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
3, SOAPMessage的传递
private String ns="http://service.soap.yangw.com/"; private String wsdlUrl="http://localhost:8899/ns?wsdl"; /** * Soap消息的传递 */ @Test public void test02() { try { //1,创建服务 URL url=new URL(wsdlUrl); QName qName=new QName(ns,"MyServiceImplService"); Service service=Service.create(url, qName); //2,创建Dispatch Dispatch<SOAPMessage> dispatch=service.createDispatch(new QName(ns,"MyServiceImplPort"),//(创建Port的时候指定名称空间) SOAPMessage.class, Service.Mode.MESSAGE); //3, 创建SOAPMessage SOAPMessage msg=MessageFactory.newInstance().createMessage(); SOAPEnvelope envelope=msg.getSOAPPart().getEnvelope(); SOAPBody body=envelope.getBody(); //4, 创建QName来指定消息中传递的数据 QName eName=new QName(ns,"add", "nn"); //前缀必须指定,名字可以任意 <nn:add xmlns="XXX" /> SOAPBodyElement bodyEle=body.addBodyElement(eName); bodyEle.addChildElement("a").setValue("22"); bodyEle.addChildElement("b").setValue("33"); msg.writeTo(System.out); //输出消息到控制台 /** * <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> * <SOAP-ENV:Header/> * <SOAP-ENV:Body> * <nn:add xmlns:nn="http://service.soap.yangw.com/"> * <a>22</a> * <b>33</b> * </nn:add> * </SOAP-ENV:Body> * </SOAP-ENV:Envelope> */ System.out.println("\n invoke ..."); //5, 通过Dispatch传递消息 SOAPMessage resMsg= dispatch.invoke(msg); resMsg.writeTo(System.out); /** * <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> * <S:Header/> * <S:Body> * <ns2:addResponse xmlns:ns2="http://service.soap.yangw.com/"> * <addResult>55</addResult> * </ns2:addResponse> * </S:Body> * </S:Envelope> */ //6, 将响应的消息转换为DOM对象 Document doc=resMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(); String str=doc.getElementsByTagName("addResult").item(0).getTextContent(); System.out.println("\n"+str); } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
4, 基于PayLoad的方式传递SOAP消息,其实是附件的形式 下面实例是传递了一个自定义User对象 它可以传递字符串
package com.yangw.soap.service; import java.util.Date; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class User { private String userName; private String password; private int age; private Date birthday; public User() { super(); } public User(String userName, String password, int age, Date birthday) { super(); this.userName = userName; this.password = password; this.age = age; this.birthday = birthday; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
package com.yangw.soap.service; 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); //返回对象是什么类型就写什么值,不区分单个对象还是List @WebResult(name="user") public User addUser(@WebParam(name="user")User user); @WebResult(name="user") public User login(@WebParam(name="username")String username,@WebParam(name="password")String password); @WebResult(name="user") public List<User> list(); }
package com.yangw.soap.service; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.jws.WebService; //说明该类是服务接口的实现类 @WebService(endpointInterface="com.yangw.soap.service.IMyService") public class MyServiceImpl implements IMyService { private static List<User> users=new ArrayList<User>(); static{ users.add(new User("yangw","123456",12,new Date())); users.add(new User("awei","123456",25,new Date())); } @Override public int add(int a, int b) { System.out.println("a+b="+(a+b)); return a+b; } @Override public User addUser(User user) { users.add(user); return user; } @Override public User login(String username, String password) { for(User user:users){ if(user.getUserName().equals(username)&&user.getPassword().equals(password)){ return user; } } return null; } @Override public List<User> list() { return users; } }
真正的处理消息的组成,发送和接收
/** * Soap消息的传递,PAYLOAD方式可以传字符串的. */ @Test public void test03() { try { //1,创建服务 URL url=new URL(wsdlUrl); QName qName=new QName(ns,"MyServiceImplService"); Service service=Service.create(url, qName); //2,创建Dispatch ,通过Source的方式传递 Dispatch<Source> dispatch=service.createDispatch(new QName(ns,"MyServiceImplPort"), Source.class, Service.Mode.PAYLOAD); //3, 根据用户对象创建相应的xml(编排) User user=new User("ahuang","123321",23,new Date()); JAXBContext ctx=JAXBContext.newInstance(User.class); Marshaller mar=ctx.createMarshaller(); //去掉文档头和尾 mar.setProperty(Marshaller.JAXB_FRAGMENT, true); StringWriter writer=new StringWriter(); mar.marshal(user, writer); //4,封装相应的Part addUser String payLoad="<nn:addUser xmlns:nn='"+ns+"'>"+writer.toString()+"</nn:addUser>"; System.out.println(payLoad); //5,通过Dispatch传递 payLoad Source response=dispatch.invoke(new StreamSource(new StringReader(payLoad))); //6, 将Source转换为DOM操作,使用Transform对象 Transformer tran=TransformerFactory.newInstance().newTransformer(); DOMResult result=new DOMResult(); tran.transform(response, result); //7,处理响应信息 XPath xpath=XPathFactory.newInstance().newXPath(); NodeList nl=(NodeList) xpath.evaluate("//user", result.getNode(),XPathConstants.NODESET); //反编排 User u=(User) ctx.createUnmarshaller().unmarshal(nl.item(0)); System.out.println(u.getUserName()); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerFactoryConfigurationError e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } catch (XPathExpressionException e) { e.printStackTrace(); } }
5, list方法测试
package com.yangw.soap.service; 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); //返回对象是什么类型就写什么值,不区分单个对象还是List @WebResult(name="user") public User addUser(@WebParam(name="user")User user); @WebResult(name="user") public User login(@WebParam(name="username")String username,@WebParam(name="password")String password); @WebResult(name="user") public List<User> list1(); @WebResult(name="user") //设置header为true,让它以头信息的形式传递 //这是显示的方式传递头部信息的方式 public List<User> list2(@WebParam(name="authInfo",header=true)String authInfo); }
不带参数的list()方法
/** * Soap消息的传递 --测试 list()方法,不带参数的形式 */ @Test public void test04() { try { //1,创建服务 URL url=new URL(wsdlUrl); QName qName=new QName(ns,"MyServiceImplService"); Service service=Service.create(url, qName); //2,创建Dispatch (创建Port的时候指定名称空间) Dispatch<SOAPMessage> dispatch=service.createDispatch(new QName(ns,"MyServiceImplPort"), SOAPMessage.class, Service.Mode.MESSAGE); //3, 创建SOAPMessage SOAPMessage msg=MessageFactory.newInstance().createMessage(); SOAPEnvelope envelope=msg.getSOAPPart().getEnvelope(); SOAPBody body=envelope.getBody(); //4, 创建QName来指定消息中传递的数据 QName eName=new QName(ns,"list1", "nn"); //前缀必须指定,名字可以任意 <nn:add xmlns="XXX" /> body.addBodyElement(eName); msg.writeTo(System.out); //输出消息到控制台 /** *<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> * <SOAP-ENV:Header/> * <SOAP-ENV:Body> * <nn:list xmlns:nn="http://service.soap.yangw.com/"/> * </SOAP-ENV:Body> *</SOAP-ENV:Envelope> */ System.out.println("\n invoke ..."); //5, 通过Dispatch传递消息 SOAPMessage resMsg= dispatch.invoke(msg); resMsg.writeTo(System.out); System.out.println(); /** *<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> * <S:Header/> * <S:Body> * <ns2:listResponse xmlns:ns2="http://service.soap.yangw.com/"> * <user> * <age>12</age> * <birthday>2014-03-03T14:21:02.468+08:00</birthday> * <password>123456</password> * <userName>yangw</userName> * </user> * <user> * <age>25</age> * <birthday>2014-03-03T14:21:02.468+08:00</birthday> * <password>123456</password> * <userName>awei</userName> * </user> * </ns2:listResponse> * </S:Body> *</S:Envelope> */ //6, 将响应的消息转换为DOM对象 Document doc=resMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(); NodeList nl=doc.getElementsByTagName("user"); JAXBContext ctx=JAXBContext.newInstance(User.class); for(int i=0;i<nl.getLength();i++){ Node node=nl.item(i); //import org.w3c.dom.Node; User user=(User) ctx.createUnmarshaller().unmarshal(node); System.out.println(user.getUserName()+":"+user.getPassword()); } } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } }
带参数的list()方法测试
/** * Soap消息的传递 --测试 list(String)方法,带参数的形式,一般都是把参数放到头信息中作验证 */ @Test public void test05() { try { //1,创建服务 URL url=new URL(wsdlUrl); QName qName=new QName(ns,"MyServiceImplService"); Service service=Service.create(url, qName); //2,创建Dispatch (创建Port的时候指定名称空间) Dispatch<SOAPMessage> dispatch=service.createDispatch(new QName(ns,"MyServiceImplPort"), SOAPMessage.class, Service.Mode.MESSAGE); //3, 创建SOAPMessage SOAPMessage msg=MessageFactory.newInstance().createMessage(); SOAPEnvelope envelope=msg.getSOAPPart().getEnvelope(); //3.2 头信息的处理 SOAPHeader header=envelope.getHeader(); if(header==null) header=envelope.addHeader(); QName hName=new QName(ns,"authInfo", "nn"); header.addHeaderElement(hName).setValue("aabbcc"); SOAPBody body=envelope.getBody(); //4, 创建QName来指定消息中传递的数据 QName eName=new QName(ns,"list2", "nn"); //前缀必须指定,名字可以任意 <nn:add xmlns="XXX" /> body.addBodyElement(eName); msg.writeTo(System.out); //输出消息到控制台 /** * <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> * <SOAP-ENV:Header> * <nn:authInfo xmlns:nn="http://service.soap.yangw.com/">aabbcc</nn:authInfo> * </SOAP-ENV:Header> * <SOAP-ENV:Body> * <nn:list2 xmlns:nn="http://service.soap.yangw.com/"/> * </SOAP-ENV:Body> * </SOAP-ENV:Envelope> */ System.out.println("\n invoke ..."); //5, 通过Dispatch传递消息 SOAPMessage resMsg= dispatch.invoke(msg); resMsg.writeTo(System.out); System.out.println(); /** *<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> * <S:Header/> * <S:Body> * <ns2:listResponse xmlns:ns2="http://service.soap.yangw.com/"> * <user> * <age>12</age> * <birthday>2014-03-03T14:21:02.468+08:00</birthday> * <password>123456</password> * <userName>yangw</userName> * </user> * <user> * <age>25</age> * <birthday>2014-03-03T14:21:02.468+08:00</birthday> * <password>123456</password> * <userName>awei</userName> * </user> * </ns2:listResponse> * </S:Body> *</S:Envelope> */ //6, 将响应的消息转换为DOM对象 Document doc=resMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(); NodeList nl=doc.getElementsByTagName("user"); JAXBContext ctx=JAXBContext.newInstance(User.class); for(int i=0;i<nl.getLength();i++){ Node node=nl.item(i); //import org.w3c.dom.Node; User user=(User) ctx.createUnmarshaller().unmarshal(node); System.out.println(user.getUserName()+":"+user.getPassword()); } } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } }
上面头消息的处理是显示消息的处理,用wsimport导出之后,可以看到会“自动生成一个List对象”
接口上的名称空间应该与实现类上的名称空间一致.