?
WebService学习之路一 :http://trylin.iteye.com/blog/1906819
?
WebService学习之路二 :http://trylin.iteye.com/blog/1907883
?
WebService学习之路三 :http://trylin.iteye.com/blog/1908269
?
SOAP 的理解使用
?
不论是以那种形式实现WS服务,axis也好,xfire,CXF也好 ,服务进行消息传替都是基于SOAP格式的。
?
这里简单理解一下SOAP信息,和实现使用SOAP格式的调用我们发布的WS.
?
1、SOAP消息格式。
打开之前的第一个简单示例的服务。
?
eclipse的视图模式改为javaee,并且打开wsdl浏览

?选择WSDL视图
?

?
?
选择一个WSDL MAIN,并输入我们发布的WSDL地址。

?看到我们发布的两个方法了吧,选择add然后输入两个参数,点击go,然后点击下发status项的 Source,
?
?

?

?
?
这样就可以看到我们请求WS的请求和返回的SOAP消息,上面是请求,下面是返回 。请求的参数都是被包裹在一个Body的对象中,然后是方法,再是方法下的参数。
?

?
?看到SOAP消息,有没有觉得和我们发布的WSDL的types的格式很像,下面截图做个简单的比较,一目了然。
?
?
?

?
2、使用SOAP消息访问WS
?
上面看到了我们请求返回的SOAP消息,那当然我们也可以根据SOAP的消息格式访问我们发布的WS服务,这就要使用到jdk扩展包下的 soap 包。
?
?
?
在我们客户端的项目中新建一个类 SOAPImpl(具体代码有注释,更多的可以看视频的中的解释哦)
学习视频地址:http://trylin.iteye.com/blog/1907289
?
WS服务端代码:(由于之前有测试过命名空间相关的东西,下面的测试都是基于默认命名空间,如果按照第一章的示例来直接用下面的客户端访问 可能会出现找不到方法的情况,或者你可以把我的测试代码的命名空间修改下,都是可以的,这里我把除去命名空间的服务端代码也贴上。。。)
?
Java代码??

- @WebService()??
- public?interface?ITest?{??
- ????int?add(@WebParam(name="a")int?a,?@WebParam(name="b")int?b);??
- ????int?minus(int?b);??
- }??
- @WebService(endpointInterface="com.trylin.ws.service.ITest")??
- class?TestImpl?implements?ITest{??
- ????int?add(int?b)?{??
- ????????System.out.println(a+"+"+b+"="+(a+b));??
- ????????return?a+b;??
- ????}??
- ????int?minus(int?b)?{??
- ????????return?a-b;??
- ????}??
- }??
?
?客户端:
Java代码??
class?SOAPImpl?{??
??????
????/**?服务地址?*/??
????public?URL?url?=?null;??
????/**?服务命名空间?*/??
????public?String?ns?=?"http://impl.service.ws.trylin.com/";??
????/**?命名空间变量?*/??
????public?String?xlns?=?"nn";??
??????
????public?SOAPImpl(){??
????????try?{??
????????????url?=?new?URL("http://localhost:8888/WS");??
????????}?catch?(MalformedURLException?e)?{??
????????????//?TODO?Auto-generated?catch?block??
????????????e.printStackTrace();??
????????}??
????}??
??????
????/**?
?????*?创建add方法的SOAP消息?
?????*?@return?
?????*?@throws?Exception?
?????*/??
????protected?SOAPMessage?add()?throws?Exception{??
????????MessageFactory?factory?=?MessageFactory.newInstance();//创建消息工厂??
????????SOAPMessage?message?=?factory.createMessage();//创建消息类型??
????????SOAPPart?part?=?message.getSOAPPart();//创建Part元素??
????????SOAPEnvelope?envelope?=?part.getEnvelope();//创建envelope元素???SOAP的根节点??
????????SOAPBody?body?=?envelope.getBody();//body对象??
????????//指定body下节点?请求的方法add元素??
????????SOAPBodyElement?bodyElement?=?body.addBodyElement(new?QName("http://service.ws.trylin.com/","add",xlns));??
????????//设置add方法的参数??
????????bodyElement.addChildElement("a").setValue("1");??
????????bodyElement.addChildElement("b").setValue("2");??
????????message.writeTo(System.out);??
????????return?message;??
????}??
??????
?????????*?通过Service将SOAP消息提交到WS服务端,并返回服务端的SOAPMessage?
public?SOAPMessage?getSOAPWS()?throws?Exception{??
????????//创建发送Service??设定Qname?TestImplService??服务名??
????????Service?service?=?Service.create(url,85)">new?QName(ns,"TestImplService"));??
????????//通过dispatch发送请求??设置请求格式为Service.Mode.MESSAGE??
????????Dispatch<SOAPMessage>?dispath?=?service.createDispatch("TestImplPort"),??
????????????????SOAPMessage.class,?Service.Mode.MESSAGE);??
????????SOAPMessage?request?=?this.add();??
????????System.out.println("n.......");??
????????SOAPMessage?response?=?dispath.invoke(request);??
????????response.writeTo(System.out);??
????????return?response;??
????}??
??????
?????????*?解析服务端的SOAPMessage?
?????*?@param?message?
void?parseSOAPMessage(SOAPMessage?message)?throws?Exception{??
????????System.out.println();??
????????Document?document?=?message.getSOAPPart()??
????????????.getEnvelope().getBody().extractContentAsDocument();//获取Body节点元素文本对象??
????????Element?element?=?document.getDocumentElement();??
????????System.out.println((element.getElementsByTagName("return").item(0).getTextContent()));//打印返回值??
????}??
}??
?
?
然后在写客户端测试用例:
?
Java代码??
class?TestSOAP?{??
????@Test??
????void?test01()?throws?Exception{??
????????SOAPImpl?soap?=?new?SOAPImpl();??
????????soap.parseSOAPMessage(soap.getSOAPWS());??
????}??
}??
?运行后,查看我们定义的soap输出和服务的返回 soap 还有返回的计算结果
?
?
?

?这个是简单的服务访问,我们添加一个自定义的User对象,在服务中再添加一个用户登录的方法,然后发布后,通过WSDL浏览器,请求login服务,看下这时的soap消息是啥样的。
首先创建一个User
?
Java代码??
class?User?{??
????private?String?userName;?//名字??
????private?int?age;//年龄??
????boolean?isBoy;//??
????double?money;//??
……省略get?set??
}??
?服务类中 添加login方法
?
?
Java代码??
int?b);??
????@WebMethod(operationName="login")??
????public?@WebResult(name="user")User?login(@WebParam(name="user")User?user);??
}??
return?a-b;??
????}??
????public?User?login(User?user){??
????????if("hiboy".equals(user.getUserName())){??
????????????user.setAge(12);??
????????????user.setBoy(true);??
????????????user.setMoney(100);??
????????????return?user;??
????????}??
????????return?null;??
????}??
}??
?这里用到了几个注释,简单说明一下:
?
?
@WebService()? 标记创建WS服务,可以设置命名空间,实现接口,服务名称等。
?
@WebParam() 表示参数在wsdl中显示的名称,默认参数名是按照arg0.. argN,可以手动设定,如@WebParam(name="a")int?a?? 这样a元素在wsdl中就显示成a而不是 arg0
?
@WebResult这个表示返回参数在wsdl显示的名称,默认返回参数名称为return,如@WebResult(name="user")User 这样在wsdl中login的返回参数名就是user了
?
@WebMethod 表示wsdl中显示的方法名,默认是按照原方法名显示,这里可以修改。
?
?
?
然后启动服务,通过WSDL浏览器访问我们的login方法,查看SOAP消息。仔细看下User的格式哦。

?
?
看到SOAP消息了,然后我们在用客户端去按照SOAP消息的格式访问WS。
?
这里的访问有两种方法,第一种就是前面说的,给body对像手动的添加节点,这样比较死,一个一个的添加,也比较累。第二种方法,可以通过JAXB 将一个User对象格式化成类似上面soap消息的xml。可以先试下第一种方法,我这里写第二种。
?
?在客户端,我们也要生成XMl对应的user对象
?
Java代码??
@XmlRootElement//注意这个注解??不加下面使用jaxB的时候会报错??
class?User?{??
??????
????//是否??
????//??
?????//...get??set??
}??
?在SOAPImpl类中新增加几个方法
?
?
?
Java代码??
?????*?设置Login的?Source对象??Source简单理解为数据源?
protected?Source?login()?throws?Exception{??
????????User?user?=?new?User();??
????????user.setUserName("hiboy");//设置参数?User??
????????JAXBContext?context?=?JAXBContext.newInstance(User.class);//创建JAXB文档对戏那个??
????????Marshaller?mar?=?context.createMarshaller();??
????????mar.setProperty(Marshaller.JAXB_FRAGMENT,85)">true);//设置生成的xml不包含xml头????
????????StringWriter?writer?=?new?StringWriter();??
????????mar.marshal(user,?writer);//处理User??
????????//JAXBContext??只处理User对像?所以方法声明的部分?还是的自己手写??
????????String?payLoad?=?"<"+xlns+":login?xmlns:"+xlns+"=""+"http://service.ws.trylin.com/"+"">"+writer.toString()+"</nn:login>";??
????????System.out.println(payLoad);??
????????//穿件?Source流对象??
????????Source?source?=?new?StreamSource(new?StringReader(payLoad));??
????????return?source;??
????}??
?????????*?通过Service将Source发送到服务端??并且返回服务端的Source?
public?Source?getSOAPLoginWS()?throws?Exception{??
????????Service?service?=?Service.create(url,"TestImplService"));??
????????Dispatch<Source>?dispath?=?service.createDispatch(????????????????Source.????????Source?request?=?this.login();??
????????Source?response?=?dispath.invoke(request);??
????????return?response;??
????}??
?????????*?解析Source?
?????*?@param?source?
void?parseSOAPSource(Source?source)?throws?Exception{??
????????System.out.println();??
????????//解析的时候?需要获得节点对象??所以此处用?Transformer转换??
????????Transformer?transformer??=?TransformerFactory.newInstance().newTransformer();??
????????DOMResult?result?=?new?DOMResult();??
????????transformer.transform(source,?result);??
????????//第一层?获取response节点???
????????Node?nl?=??result.getNode().getFirstChild().getFirstChild();??
????????JAXBContext?context?=?JAXBContext.newInstance(User.class);??
????????Unmarshaller?umar?=?context.createUnmarshaller();??
????????User?user?=?(User)umar.unmarshal(nl);??
????????System.out.println(user.getMoney());??
????}??
?
编写测试类:
Java代码??
@Test??
void?test02()?throws?Exception{??
????SOAPImpl?soap?=?new?SOAPImpl();??
????soap.parseSOAPSource(soap.getSOAPLoginWS());??
}??
?运行 输出 : ?100.0就是我们在服务端 给User加的一个值,这样表示通过SOAP调用成功。

?
还是那句话,本人技术不牢靠,可能整理的这些有点乱,也没有按照视频上的原样规规矩矩的记录所有。也有一些内容都是自己的理解,肯定有理解有误的地方。这里解释不详细的,有错误的,还行看到博客的大神在回复中留下你们的间接,如果有幸有童鞋模仿上面的示例,有问题的也可以提出,我们一起解决。。。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!