`

基于JAX-WS调用Web Service的Java客户端

 
阅读更多

基于JAX-WS调用Web Service的Java客户端一般采用两种方式:proxy方式以及dispatch方式。

proxy方式 ,proxy的步骤主要如下图所示:

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

URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");
QName serviceQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderService");
QName portQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderPort");
Service service = Service.create(wsdlURL, serviceQName);
WSCXFProvider port = (WSCXFProvider) service.getPort(portQName, WSCXFProvider.class);
try{
System.out.println(port.testWS("message"));
}catch(SOAPFaultException e){
System.out.println(e.getFault().getFaultCode());
System.out.println(e.getFault().getFaultString());
}

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。

payload方式 通过JAXB Java对象:

示例代码:

// create Service
URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");
QName serviceQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderService");
Service service = Service.create(wsdlURL, serviceQName);
JAXBContext ctxt = JAXBContext.newInstance(MyRequest.class, MyResponse.class);
QName portQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderPort");
Dispatch<Object> dispatchJAXB = service.createDispatch(portQName, ctxt, Service.Mode.PAYLOAD);
// create the custom request order object
MyRequest myReq = new MyRequest();
myReq.arg0="message";
MyResponse resp = (MyResponse) dispatchJAXB.invoke(myReq);
System.out.println(resp.get_return());

MyRequest是加上JAXB 标注的类:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "testWS", propOrder = {
"arg0"
})
@XmlRootElement(name = "testWS")
public class MyRequest {
protected String arg0;
public String getArg0() {
return arg0;
}
public void setArg0(String arg0) {
this.arg0 = arg0;
}
}

MyResponse也是加上JAXB 标注的类:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "testWSResponse", propOrder = {
"_return"
})
@XmlRootElement(name = "testWSResponse", namespace="http://test.cxf.bt.com/")
public class MyResponse {
@XmlElement(name = "return")
protected String _return;
public String get_return() {
return _return;
}
public void set_return(String _return) {
this._return = _return;
}
}

某些工具生成的JAXB客户端(MyRequest和MyResponse)会没有加上@XmlRootElement,这时候会报* unable to marshal type "....." as an element because it is missing an @XmlRootElement annotation],候需要手动的加上XmlRootElement注解.

payload方式 通过XML source: 传入xml的payload内容。

StreamSource xmlSource = new StreamSource(new StringReader(
"<dlwmin:testWS xmlns:dlwmin=/"http://test.cxf.bt.com//"><arg0>xxx</arg0></dlwmin:testWS> "));
// create Service
URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");
QName serviceQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderService");
Service service = Service.create(wsdlURL, serviceQName);
// create Dispatch<Source>
QName portQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderPort");
Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
Source orderSource = dispatch.invoke(xmlSource);
// Process the response.
StreamResult result = new StreamResult(new ByteArrayOutputStream());
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.transform(orderSource, result);
ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
// Write out the response content.
String responseContent = new String(baos.toByteArray());
System.out.println(responseContent);

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

StreamSource xmlSource1 = new StreamSource(
new StringReader(
"<?xml version=/"1.0/" encoding=/"utf-8/" ?><SOAP-ENV:Envelope xmlns:SOAP-ENV=/"http://schemas.xmlsoap.org/soap/envelope//" xmlns:xsd=/"http://www.w3.org/2001/XMLSchema/" xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/"><SOAP-ENV:Header/><SOAP-ENV:Body><dlwmin:testWS xmlns:dlwmin=/"http://test.cxf.bt.com//"><arg0>xxx</arg0></dlwmin:testWS></SOAP-ENV:Body></SOAP-ENV:Envelope> "));

// create Service
URL wsdlURL = new URL("file:///D:/JAVAWorkspace/Test/WSClient/src/wsdl/prjCXFWeb.wsdl");
QName serviceQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderService");
Service service = Service.create(wsdlURL, serviceQName);

// create Dispatch<Source>
QName portQName = new QName("http://test.cxf.bt.com/", "WSCXFProviderPort");
Dispatch<SOAPMessage> dispatch = service.createDispatch(portQName, SOAPMessage.class, Service.Mode.MESSAGE);

MessageFactory factory = MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();
message.getSOAPPart().setContent(xmlSource1);
message.saveChanges();
SOAPMessage response = dispatch.invoke(message);
SOAPPart sp = response.getSOAPPart();
Source resp = sp.getContent();

// Process the response.
StreamResult result = new StreamResult(new ByteArrayOutputStream());
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.transform(resp, result);
ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();

// Write out the response content.
String responseContent = new String(baos.toByteArray());
System.out.println(responseContent);

JAX-WS仍然支持使用RPC方式调用,但已经完全不鼓励使用(服务器端的服务提供类必须extends Remote).下面是一个客服端的调用例子:

引入的是 javax.xml.rpc 下的类.
package com.test.jaxws.caller;

import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.ServiceFactory;

import com.cxfws.test.SimpleService;

public class JAXRPCWSCaller {
static String wsdlLocation = "file:///D:/JAVAWorkspace/Repository/prjCXFWS/src/wsdl/prjCXFWS.wsdl";

// SimpleService must extends Remote if using this way to call web service
public static void main(String[] args) throws MalformedURLException, ServiceException, RemoteException {

ServiceFactory serviceFactory = ServiceFactory.newInstance();

Service service = serviceFactory.createService(new URL(wsdlLocation), new QName("http://test.cxfws.com/",
"SimpleServiceService"));

SimpleService myProxy = (SimpleService) service.getPort(
new QName("http://test.cxfws.com/", "SimpleServicePort"), SimpleService.class);

String result = myProxy.concatenate("s1", "s2");
System.out.println(result);

}
}

而如果服务器端不是JAVA实现,那就只能用soap.jar的rpc.Call了[下面的例子是一个很古老的代码了...]

/*
* Created on Sep 19, 2006
*
* To change the template for this generated file go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
package com.test.soaprpc.caller;

import java.net.URL;
import java.util.Arrays;
import java.util.Vector;

import org.apache.soap.Constants;
import org.apache.soap.Fault;
import org.apache.soap.Header;
import org.apache.soap.encoding.SOAPMappingRegistry;
import org.apache.soap.encoding.soapenc.StringDeserializer;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Parameter;
import org.apache.soap.rpc.Response;
import org.apache.soap.util.xml.QName;


public class WSCallerBySOAP {
public Object callWS(Parameter[] params, String uri, String mtdName, String url, SOAPMappingRegistry smr) {

try {
Call call = new Call();

call.setTargetObjectURI(uri);
call.setMethodName(mtdName);
call.setParams(new Vector(Arrays.asList(params)));

call.setSOAPMappingRegistry(smr);


Header myHeader = new Header();
myHeader.declareNamespace("", " XXX ");
myHeader.setAttribute(new QName("", "Minor"), "0");
call.setHeader(myHeader);

Response resp = call.invoke(new URL(url), "");

if (resp.generatedFault()) {
Fault fault = resp.getFault();
System.out.println(fault.getFaultCode());
System.out.println(fault.getFaultString());
} else {
if (resp.getReturnValue() != null) {
Object obj = resp.getReturnValue().getValue();
return obj;

}

}
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
return null;

}

public static void main(String[] args) {
WSCallerBySOAP wsCaller = new WSCallerBySOAP();
Parameter param1 = new Parameter("arg0", String.class, "<test:testWS>" + "<arg0>aaaaaaaaaa</arg0>"
+ "</test:testWS>", Constants.NS_URI_SOAP_ENC);

Parameter[] prams = new Parameter[] { param1 };
String uri = "WSCXFProviderPort";
String url = "http://localhost:7225/prjCXFWeb/services/WSCXFProviderPort";
String mtdName = "testWS";

SOAPMappingRegistry smr = new SOAPMappingRegistry();
smr.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("", "return"), null, null, new StringDeserializer());

System.out.println(wsCaller.callWS(prams, uri, mtdName, url, smr));

}

}

分享到:
评论

相关推荐

    jax-ws 方式发布web Service 后台用Hibernate实现,前端.NET通过引用服务方式实现

    rar中包含整个项目的源码和数据库生成脚本,采用jax-ws发布Web Service服务,支持java客户端和.Net客户端调用,数据库采用oracle10g,里面有创建数据库脚本文件createTable_Oracle10g.sql,由于Hibernate映射表中会...

    JAX-WS自学笔记

    JAX-WS自学笔记 本人自学JAX-WS笔记和简单例子,文档标题结构如下: ...2.4.1.4 调用Web Service 2.5 SOAP headers 2.5.1 客户端添加SOAP headers 2.5.2 访问SOAP headers 2.5.2.1 服务器端 2.5.2.2 客户端

    WebService之JAX-WS自学笔记

    自己自学JAX-WS的心得,内含较为详细的讲解了简单的例子。...2.4.1.4 调用Web Service 2.5 SOAP headers 2.5.1 客户端添加SOAP headers 2.5.2 访问SOAP headers 2.5.2.1 服务器端 2.5.2.2 客户端

    Spring 实现远程访问详解——rmi

    6. JAX-WS:Spring通过JAX-WS为远程Web服务提供支持(the successor of JAX-RPC, as introduced in Java EE 5 and Java 6)。 7. JMS:远程访问通过类JmsInvokerServiceExporter和JmsInvokerProxyFactoryBean使用JMS的...

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

    中文名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 原名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 作者: 李刚 资源格式: PDF 版本: 第一版 出版社: 电子...

    BOS技术整理-05

    3.更易于实现缓存机制(第一次访问资源缓存,第二次访问资源,返回304客户端调用本地) JAX-RS整合spring服务器端开发 建立 maven web项目,演示RS整合spring服务发布 pom文件中导入坐标 web.xml配置...

    Spring中文帮助文档

    2.5.7. JAX-WS支持 2.6. 其他 2.6.1. 动态语言支持 2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到...

    Spring API

    2.5.7. JAX-WS支持 2.6. 其他 2.6.1. 动态语言支持 2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到...

    Java™ Servlet 规范.

    目录 ...2.3.4 终止服务(End of Service) .........................................................................................................27 Request .............................

    Servlet3.1规范(最终版) PDF

    2.1 请求处理方法 ...........................................................................................................................................15 2.1.1 基于 Http 规范的请求处理方法 .........

Global site tag (gtag.js) - Google Analytics