当前位置 : 主页 > 网页制作 > Nodejs >

WebService学习之路四

来源:互联网 收集:自由互联 发布时间:2021-06-24
WebService学习之路一 :http://trylin.iteye.com/blog/1906819 WebService学习之路二 :http://trylin.iteye.com/blog/1907883 WebService学习之路三 :http://trylin.iteye.com/blog/1908269 SOAP 的理解使用 不论是以那种形式

 

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代码  
  1. @WebService()  
  2. public interface ITest {  
  3.     public int add(@WebParam(name="a")int a, @WebParam(name="b")int b);  
  4.     public int minus(@WebParam(name="a")int a, @WebParam(name="b")int b);  
  5. }  
  6. @WebService(endpointInterface="com.trylin.ws.service.ITest")  
  7. public class TestImpl implements ITest{  
  8.     public int add(int a, int b) {  
  9.         System.out.println(a+"+"+b+"="+(a+b));  
  10.         return a+b;  
  11.     }  
  12.     public int minus(int a, int b) {  
  13.         return a-b;  
  14.     }  
  15. }  

 

 客户端:

Java代码  
  1. public class SOAPImpl {  
  2.       
  3.     /** 服务地址 */  
  4.     public URL url = null;  
  5.     /** 服务命名空间 */  
  6.     public String ns = "http://impl.service.ws.trylin.com/";  
  7.     /** 命名空间变量 */  
  8.     public String xlns = "nn";  
  9.       
  10.     public SOAPImpl(){  
  11.         try {  
  12.             url = new URL("http://localhost:8888/WS");  
  13.         } catch (MalformedURLException e) {  
  14.             // TODO Auto-generated catch block  
  15.             e.printStackTrace();  
  16.         }  
  17.     }  
  18.       
  19.     /** 
  20.      * 创建add方法的SOAP消息 
  21.      * @return 
  22.      * @throws Exception 
  23.      */  
  24.     protected SOAPMessage add() throws Exception{  
  25.         MessageFactory factory = MessageFactory.newInstance();//创建消息工厂  
  26.         SOAPMessage message = factory.createMessage();//创建消息类型  
  27.         SOAPPart part = message.getSOAPPart();//创建Part元素  
  28.         SOAPEnvelope envelope = part.getEnvelope();//创建envelope元素   SOAP的根节点  
  29.         SOAPBody body = envelope.getBody();//body对象  
  30.         //指定body下节点 请求的方法add元素  
  31.         SOAPBodyElement bodyElement = body.addBodyElement(new QName("http://service.ws.trylin.com/","add",xlns));  
  32.         //设置add方法的参数  
  33.         bodyElement.addChildElement("a").setValue("1");  
  34.         bodyElement.addChildElement("b").setValue("2");  
  35.         message.writeTo(System.out);  
  36.         return message;  
  37.     }  
  38.       
  39.     /** 
  40.      * 通过Service将SOAP消息提交到WS服务端,并返回服务端的SOAPMessage 
  41.      * @return 
  42.      * @throws Exception 
  43.      */  
  44.     public SOAPMessage getSOAPWS() throws Exception{  
  45.         //创建发送Service  设定Qname TestImplService  服务名  
  46.         Service service = Service.create(url, new QName(ns,"TestImplService"));  
  47.         //通过dispatch发送请求  设置请求格式为Service.Mode.MESSAGE  
  48.         Dispatch<SOAPMessage> dispath = service.createDispatch(new QName(ns,"TestImplPort"),  
  49.                 SOAPMessage.class, Service.Mode.MESSAGE);  
  50.         SOAPMessage request = this.add();  
  51.         System.out.println("\n.......");  
  52.         SOAPMessage response = dispath.invoke(request);  
  53.         response.writeTo(System.out);  
  54.         return response;  
  55.     }  
  56.       
  57.     /** 
  58.      * 解析服务端的SOAPMessage 
  59.      * @param message 
  60.      * @throws Exception 
  61.      */  
  62.     public void parseSOAPMessage(SOAPMessage message) throws Exception{  
  63.         System.out.println();  
  64.         Document document = message.getSOAPPart()  
  65.             .getEnvelope().getBody().extractContentAsDocument();//获取Body节点元素文本对象  
  66.         Element element = document.getDocumentElement();  
  67.         System.out.println((element.getElementsByTagName("return").item(0).getTextContent()));//打印返回值  
  68.     }  
  69. }  

 

 

然后在写客户端测试用例:

 

Java代码  
  1. public class TestSOAP {  
  2.     @Test  
  3.     public void test01() throws Exception{  
  4.         SOAPImpl soap = new SOAPImpl();  
  5.         soap.parseSOAPMessage(soap.getSOAPWS());  
  6.     }  
  7. }  

 运行后,查看我们定义的soap输出和服务的返回 soap 还有返回的计算结果

 

 

 




 这个是简单的服务访问,我们添加一个自定义的User对象,在服务中再添加一个用户登录的方法,然后发布后,通过WSDL浏览器,请求login服务,看下这时的soap消息是啥样的。

首先创建一个User

 

Java代码  
  1. public class User {  
  2.     private String userName; //名字  
  3.     private int age;//年龄  
  4.     private boolean isBoy;//  
  5.     private double money;//  
  6. ……省略get set  
  7. }  

 服务类中 添加login方法

 

 

Java代码  
  1. @WebService()  
  2. public interface ITest {  
  3.     public int add(@WebParam(name="a")int a, @WebParam(name="b")int b);  
  4.     public int minus(@WebParam(name="a")int a, @WebParam(name="b")int b);  
  5.     @WebMethod(operationName="login")  
  6.     public @WebResult(name="user")User login(@WebParam(name="user")User user);  
  7. }  
  8. @WebService(endpointInterface="com.trylin.ws.service.ITest")  
  9. public class TestImpl implements ITest{  
  10.     public int add(int a, int b) {  
  11.         System.out.println(a+"+"+b+"="+(a+b));  
  12.         return a+b;  
  13.     }  
  14.     public int minus(int a, int b) {  
  15.         return a-b;  
  16.     }  
  17.     public User login(User user){  
  18.         if("hiboy".equals(user.getUserName())){  
  19.             user.setAge(12);  
  20.             user.setBoy(true);  
  21.             user.setMoney(100);  
  22.             return user;  
  23.         }  
  24.         return null;  
  25.     }  
  26. }  

 这里用到了几个注释,简单说明一下:

 

 

@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代码  
  1. @XmlRootElement//注意这个注解  不加下面使用jaxB的时候会报错  
  2. public class User {  
  3.       
  4.     private String userName; //名字  
  5.     private int age;//年龄  
  6.     private boolean isBoy;//是否  
  7.     private double money;//  
  8.      //...get  set  
  9. }  

 在SOAPImpl类中新增加几个方法

 

 

 

Java代码  
  1. /** 
  2.      * 设置Login的 Source对象  Source简单理解为数据源 
  3.      * @return 
  4.      * @throws Exception 
  5.      */  
  6.     protected Source login() throws Exception{  
  7.         User user = new User();  
  8.         user.setUserName("hiboy");//设置参数 User  
  9.         JAXBContext context = JAXBContext.newInstance(User.class);//创建JAXB文档对戏那个  
  10.         Marshaller mar = context.createMarshaller();  
  11.         mar.setProperty(Marshaller.JAXB_FRAGMENT, true);//设置生成的xml不包含xml头    
  12.         StringWriter writer = new StringWriter();  
  13.         mar.marshal(user, writer);//处理User  
  14.         //JAXBContext  只处理User对像 所以方法声明的部分 还是的自己手写  
  15.         String payLoad = "<"+xlns+":login xmlns:"+xlns+"=\""+"http://service.ws.trylin.com/"+"\">"+writer.toString()+"</nn:login>";  
  16.         System.out.println(payLoad);  
  17.         //穿件 Source流对象  
  18.         Source source = new StreamSource(new StringReader(payLoad));  
  19.         return source;  
  20.     }  
  21.     /** 
  22.      * 通过Service将Source发送到服务端  并且返回服务端的Source 
  23.      * @return 
  24.      * @throws Exception 
  25.      */  
  26.     public Source getSOAPLoginWS() throws Exception{  
  27.         Service service = Service.create(url, new QName(ns,"TestImplService"));  
  28.         Dispatch<Source> dispath = service.createDispatch(new QName(ns,"TestImplPort"),   
  29.                 Source.class, Service.Mode.PAYLOAD);  
  30.         Source request = this.login();  
  31.         Source response = dispath.invoke(request);  
  32.         return response;  
  33.     }  
  34.     /** 
  35.      * 解析Source 
  36.      * @param source 
  37.      * @throws Exception 
  38.      */  
  39.     public void parseSOAPSource(Source source) throws Exception{  
  40.         System.out.println();  
  41.         //解析的时候 需要获得节点对象  所以此处用 Transformer转换  
  42.         Transformer transformer  = TransformerFactory.newInstance().newTransformer();  
  43.         DOMResult result = new DOMResult();  
  44.         transformer.transform(source, result);  
  45.         //第一层 获取response节点   
  46.         Node nl =  result.getNode().getFirstChild().getFirstChild();  
  47.         JAXBContext context = JAXBContext.newInstance(User.class);  
  48.         Unmarshaller umar = context.createUnmarshaller();  
  49.         User user = (User)umar.unmarshal(nl);  
  50.         System.out.println(user.getMoney());  
  51.     }  

 

编写测试类:

Java代码  
  1. @Test  
  2. public void test02() throws Exception{  
  3.     SOAPImpl soap = new SOAPImpl();  
  4.     soap.parseSOAPSource(soap.getSOAPLoginWS());  
  5. }  

 运行 输出 :  100.0就是我们在服务端 给User加的一个值,这样表示通过SOAP调用成功。



 

还是那句话,本人技术不牢靠,可能整理的这些有点乱,也没有按照视频上的原样规规矩矩的记录所有。也有一些内容都是自己的理解,肯定有理解有误的地方。这里解释不详细的,有错误的,还行看到博客的大神在回复中留下你们的间接,如果有幸有童鞋模仿上面的示例,有问题的也可以提出,我们一起解决。。。

网友评论