JAX-WS和JAX-RPC方式调用Web Service的Java客户端

基于JAX-WS调用Web Service的Java客户端一般采用两种方式:proxy方式以及dispatch方式。
proxy方式,proxy的步骤主要如下图所示:

一,proxy方式的调用代码片段一般如下:

[java]  view plain copy
  1. URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");  
  2. QName serviceQName = new QName("http://test.cxf.bt.com/""WSCXFProviderService");  
  3. QName portQName = new QName("http://test.cxf.bt.com/""WSCXFProviderPort");  
  4. Service service = Service.create(wsdlURL, serviceQName);  
  5. WSCXFProvider port = (WSCXFProvider) service.getPort(portQName, WSCXFProvider.class);  
  6. try{  
  7.     System.out.println(port.testWS("message"));  
  8. }catch(SOAPFaultException e){  
  9.     System.out.println(e.getFault().getFaultCode());  
  10.     System.out.println(e.getFault().getFaultString());  
  11. }  
1,用工具通过WSDL文件产生一个SEI(service endpoint interface),一个java的interface,能够对应该web service提供的功能。这个interface的类名会对应到WSDL的portType名称,方法会和operation对应,方法的参数会和message以及types对应。CXF和Axis都提供这样的工具:wsdl2java。【上面的WSCXFProvider就是SEI】
2,初始化Service,指定wsdL URL和service的QName,service的QName的前一部分是命名空间,后一部分是名称,与WSDL文件中的<wsdl:service name="WSCXFProviderService">部分对应。然后通过getPort得到一个实现了SEI的实例,这个实例被叫做Proxy。它的QName与 wsdl文件中的<wsdl:port name="WSCXFProviderPort"部分对应。
3,通过SEI调用web service,传给SEI的参数是加上JAXB annotation的java类(简单类型和String不用标记)。
4,传入的参数被序列化为SOAP消息的payload(body部分的xml),这是因为service.getPort是通过proxy机制创建的,调用这个proxy的方法时,和它关联的InvocationHandler的invoke方法也会执行,invoke方法会通过JAXB把java参数序列化为XML。然后会把soap request发到服务器端。
5,返回response是后与4类似,InvocationHandler负责把XML利用JAXB反序列化为java对象。

二,Dispatch方式:dispatch有payload方式和message方式。
在payload方式中,客户端需要关心的是 SOAP消息中的body部分,可以通过把带有JAXB注解的Java对象或者XML source两种方法传递给dispatch来调用Web service。
1,payload方式通过JAXB Java对象:
示例代码:
[java]  view plain copy
  1. // create Service  
  2. URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");  
  3. QName serviceQName = new QName("http://test.cxf.bt.com/""WSCXFProviderService");  
  4. Service service = Service.create(wsdlURL, serviceQName);  
  5. JAXBContext ctxt = JAXBContext.newInstance(MyRequest.class, MyResponse.class);  
  6. QName portQName = new QName("http://test.cxf.bt.com/""WSCXFProviderPort");  
  7. Dispatch<Object> dispatchJAXB = service.createDispatch(portQName, ctxt, Service.Mode.PAYLOAD);  
  8. // create the custom request order object  
  9. MyRequest myReq = new MyRequest();  
  10. myReq.arg0="message";  
  11. MyResponse resp = (MyResponse) dispatchJAXB.invoke(myReq);  
  12. System.out.println(resp.get_return());  

MyRequest是加上JAXB 标注的类:
[java]  view plain copy
  1. @XmlAccessorType(XmlAccessType.FIELD)  
  2. @XmlType(name = "testWS", propOrder = {  
  3.     "arg0"  
  4. })  
  5. @XmlRootElement(name = "testWS")  
  6. public class MyRequest {  
  7.      protected String arg0;  
  8.     public String getArg0() {  
  9.         return arg0;  
  10.     }  
  11.     public void setArg0(String arg0) {  
  12.         this.arg0 = arg0;  
  13.     }  
  14. }  
MyResponse也是加上JAXB 标注的类:
[java]  view plain copy
  1. @XmlAccessorType(XmlAccessType.FIELD)  
  2. @XmlType(name = "testWSResponse", propOrder = {  
  3.     "_return"  
  4. })  
  5. @XmlRootElement(name = "testWSResponse", namespace="http://test.cxf.bt.com/")  
  6. public class MyResponse {  
  7.     @XmlElement(name = "return")  
  8.     protected String _return;  
  9.     public String get_return() {  
  10.         return _return;  
  11.     }  
  12.     public void set_return(String _return) {  
  13.         this._return = _return;  
  14.     }     
  15. }  
某些工具生成的JAXB客户端(MyRequest和MyResponse)会没有加上@XmlRootElement,这时候会报* unable to marshal type "....." as an element because it is missing an @XmlRootElement annotation],候需要手动的加上XmlRootElement注解.

2.1,payload方式通过XML source:只传入xml的payload部分的内容,不需要SOAP消息的envelope部分。

[java]  view plain copy
  1. StreamSource xmlSource = new StreamSource(new StringReader(  
  2.         "<dlwmin:testWS xmlns:dlwmin=/"http://test.cxf.bt.com//"><arg0>xxx</arg0></dlwmin:testWS>"));  
  3. // create Service  
  4. URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");  
  5. QName serviceQName = new QName("http://test.cxf.bt.com/""WSCXFProviderService");  
  6. Service service = Service.create(wsdlURL, serviceQName);  
  7. // create Dispatch<Source>  
  8. QName portQName = new QName("http://test.cxf.bt.com/""WSCXFProviderPort");  
  9. Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);  
  10. Source orderSource = dispatch.invoke(xmlSource);  
  11. // Process the response.  
  12. StreamResult result = new StreamResult(new ByteArrayOutputStream());  
  13. Transformer trans = TransformerFactory.newInstance().newTransformer();  
  14. trans.transform(orderSource, result);  
  15. ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();  
  16. // Write out the response content.  
  17. String responseContent = new String(baos.toByteArray());  
  18. System.out.println(responseContent);  

2.2,message方式通过XML source:传入整个的soap消息的xml内容。

[java]  view plain copy
  1. StreamSource xmlSource1 = new StreamSource(  
  2.     new StringReader(  
  3.             "<?xml version=/"1.0/" encoding=/"utf-8/" ?>  
  4. <SOAP-ENV:Envelope xmlns:SOAP-ENV=/"http://schemas.xmlsoap.org/soap/envelope//"   
  5. xmlns:xsd=/"http://www.w3.org/2001/XMLSchema/" xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/">  
  6. <SOAP-ENV:Header/><SOAP-ENV:Body><dlwmin:testWS xmlns:dlwmin=/"http://test.cxf.bt.com//">  
  7. <arg0>xxx</arg0></dlwmin:testWS></SOAP-ENV:Body></SOAP-ENV:Envelope>"));  
  8.   
  9. // create Service  
  10. URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");  
  11. QName serviceQName = new QName("http://test.cxf.bt.com/""WSCXFProviderService");  
  12. Service service = Service.create(wsdlURL, serviceQName);  
  13.   
  14. // create Dispatch<Source>  
  15. QName portQName = new QName("http://test.cxf.bt.com/""WSCXFProviderPort");  
  16. Dispatch<SOAPMessage> dispatch = service.createDispatch(portQName, SOAPMessage.class, Service.Mode.MESSAGE);  
  17.   
  18. MessageFactory factory = MessageFactory.newInstance();  
  19. SOAPMessage message = factory.createMessage();  
  20. message.getSOAPPart().setContent(xmlSource1);  
  21. message.saveChanges();  
  22. SOAPMessage response = dispatch.invoke(message);  
  23. SOAPPart sp = response.getSOAPPart();  
  24. Source resp = sp.getContent();  
  25.   
  26. // Process the response.  
  27. StreamResult result = new StreamResult(new ByteArrayOutputStream());  
  28. Transformer trans = TransformerFactory.newInstance().newTransformer();  
  29. trans.transform(resp, result);  
  30. ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();  
  31.   
  32. // Write out the response content.  
  33. String responseContent = new String(baos.toByteArray());  
  34. System.out.println(responseContent);  
2.3,JAX-WS仍然支持使用RPC方式调用 ,但已经完全不鼓励使用(服务器端的服务提供类必须extends Remote).下面是一个客服端的调用例子:引入的是javax.xml.rpc包下的类.
[java]  view plain copy
  1. package com.test.jaxws.caller;  
  2.   
  3. import java.net.MalformedURLException;  
  4. import java.net.URL;  
  5. import java.rmi.RemoteException;  
  6. import javax.xml.namespace.QName;  
  7. import javax.xml.rpc.Service;  
  8. import javax.xml.rpc.ServiceException;  
  9. import javax.xml.rpc.ServiceFactory;  
  10. import com.cxfws.test.SimpleService;  
  11.   
  12. public class JAXRPCWSCaller {  
  13.     static String wsdlLocation = "file:///D:/JAVAWorkspace/Repository/prjCXFWS/src/wsdl/prjCXFWS.wsdl";  
  14.   
  15.     // SimpleService must extends Remote if using this way to call web service  
  16.     public static void main(String[] args) throws MalformedURLException, ServiceException, RemoteException {  
  17.   
  18.         ServiceFactory serviceFactory = ServiceFactory.newInstance();  
  19.   
  20.         Service service = serviceFactory.createService(new URL(wsdlLocation), new QName("http://test.cxfws.com/",  
  21.                 "SimpleServiceService"));  
  22.   
  23.         SimpleService myProxy = (SimpleService) service.getPort(  
  24.                 new QName("http://test.cxfws.com/""SimpleServicePort"), SimpleService.class);  
  25.   
  26.         String result = myProxy.concatenate("s1""s2");  
  27.         System.out.println(result);  
  28.   
  29.     }  
  30. }  
2.4,而如果服务器端不是JAVA实现,那就只能用soap.jar的rpc.Call了[下面的例子是一个很古老的代码了...]
[java]  view plain copy
  1. package com.test.soaprpc.caller;  
  2.   
  3. import java.net.URL;  
  4. import java.util.Arrays;  
  5. import java.util.Vector;  
  6.   
  7. import org.apache.soap.Constants;  
  8. import org.apache.soap.Fault;  
  9. import org.apache.soap.Header;  
  10. import org.apache.soap.encoding.SOAPMappingRegistry;  
  11. import org.apache.soap.encoding.soapenc.StringDeserializer;  
  12. import org.apache.soap.rpc.Call;  
  13. import org.apache.soap.rpc.Parameter;  
  14. import org.apache.soap.rpc.Response;  
  15. import org.apache.soap.util.xml.QName;  
  16.   
  17. public class WSCallerBySOAP {  
  18.     public Object callWS(Parameter[] params, String uri, String mtdName, String url, SOAPMappingRegistry smr) {  
  19.          
  20.         try {  
  21.             Call call = new Call();  
  22.      
  23.             call.setTargetObjectURI(uri);  
  24.             call.setMethodName(mtdName);  
  25.             call.setParams(new Vector(Arrays.asList(params)));  
  26.              
  27.             call.setSOAPMappingRegistry(smr);  
  28.              
  29.             Header myHeader = new Header();  
  30.             myHeader.declareNamespace(""" XXX ");  
  31.             myHeader.setAttribute(new QName("""Minor"), "0");  
  32.             call.setHeader(myHeader);  
  33.   
  34.             Response resp = call.invoke(new URL(url), "");  
  35.              
  36.             if (resp.generatedFault()) {  
  37.                 Fault fault = resp.getFault();  
  38.                 System.out.println(fault.getFaultCode());  
  39.                 System.out.println(fault.getFaultString());  
  40.             } else {  
  41.                 if (resp.getReturnValue() != null) {  
  42.                     Object obj = resp.getReturnValue().getValue();  
  43.                     return obj;  
  44.                 }  
  45.             }  
  46.         } catch (Exception e) {  
  47.             e.printStackTrace();  
  48.             System.out.println(e);  
  49.         }  
  50.         return null;  
  51.     }  
  52.     public static void main(String[] args) {  
  53.         WSCallerBySOAP wsCaller = new WSCallerBySOAP();  
  54.         Parameter param1 = new Parameter("arg0", String.class"<test:testWS>" + "<arg0>aaaaaaaaaa</arg0>"  
  55.                 + "</test:testWS>", Constants.NS_URI_SOAP_ENC);  
  56.   
  57.         Parameter[] prams = new Parameter[] { param1 };  
  58.         String uri = "WSCXFProviderPort";  
  59.         String url = "http://localhost:7225/prjCXFWeb/services/WSCXFProviderPort";  
  60.         String mtdName = "testWS";  
  61.   
  62.         SOAPMappingRegistry smr = new SOAPMappingRegistry();  
  63.         smr.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("""return"), nullnullnew StringDeserializer());  
  64.   
  65.         System.out.println(wsCaller.callWS(prams, uri, mtdName, url, smr));  
  66.     }  
  67. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值