在Python中,我可以很容易地使用web服务:
from suds.client import Client
client = Client('http://www.example.org/MyService/wsdl/myservice.wsdl') #create client
result = client.service.myWSMethod("Bubi", 15) #invoke method
print result #print the result returned by the WS method
我想用Java实现如此简单的用法
使用Axis或CXF,您必须创建一个web服务客户端,即一个复制所有web服务方法的包,以便我们可以像调用正常方法一样调用它们。让我们称之为代理类;它们通常由wsdl2java工具生成。
实用且用户友好。但是,每当我添加/修改web服务方法并希望在客户端程序中使用它时,我都需要重新生成代理类。
所以我发现CXFDynamicClientFactory
,这种技术避免了使用代理类:
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.dynamic.DynamicClientFactory;
//...
//create client
DynamicClientFactory dcf = DynamicClientFactory.newInstance();
Client client = dcf.createClient("http://www.example.org/MyService/wsdl/myservice.wsdl");
//invoke method
Object[] res = client.invoke("myWSMethod", "Bubi");
//print the result
System.out.println("Response:n" + res[0]);
但不幸的是,它在运行时创建和编译代理类,因此需要在生产机器上使用JDK。我必须避免这种情况,或者至少我不能依赖它
我的问题:
有没有其他方法可以在Java中日常调用web服务的任何方法,而无需在运行时使用JDK,也无需生成"静态"代理类?也许去另一个图书馆?谢谢
我知道这是一个很老的问题,但如果你仍然感兴趣,你可以使用soap-wsgithub项目:https://github.com/reficio/soap-ws
这里有一个非常简单的用法示例:
Wsdl wsdl = Wsdl.parse("http://www.webservicex.net/CurrencyConvertor.asmx?WSDL");
SoapBuilder builder = wsdl.binding()
.localPart("CurrencyConvertorSoap")
.find();
SoapOperation operation = builder.operation()
.soapAction("http://www.webserviceX.NET/ConversionRate")
.find();
Request request = builder.buildInputMessage(operation)
SoapClient client = SoapClient.builder()
.endpointUrl("http://www.webservicex.net/CurrencyConvertor.asmx")
.build();
String response = client.post(request);
正如你所看到的,这真的很简单。
使用CXF 3.x,StaxDataBinding可以实现这一点。按照以下步骤学习基本知识。当然,这可以根据您的需要进行增强。
-
创建StaxDataBinding,如下所示。请注意,下面的代码可以根据您的复杂程度进行增强。
class StaxDataBinding extends AbstractInterceptorProvidingDataBinding { private XMLStreamDataReader xsrReader; private XMLStreamDataWriter xswWriter; public StaxDataBinding() { super(); this.xsrReader = new XMLStreamDataReader(); this.xswWriter = new XMLStreamDataWriter(); inInterceptors.add(new StaxInEndingInterceptor(Phase.POST_INVOKE)); inFaultInterceptors.add(new StaxInEndingInterceptor(Phase.POST_INVOKE)); inInterceptors.add(RemoveStaxInEndingInterceptor.INSTANCE); inFaultInterceptors.add(RemoveStaxInEndingInterceptor.INSTANCE); } static class RemoveStaxInEndingInterceptor extends AbstractPhaseInterceptor<Message> { static final RemoveStaxInEndingInterceptor INSTANCE = new RemoveStaxInEndingInterceptor(); public RemoveStaxInEndingInterceptor() { super(Phase.PRE_INVOKE); addBefore(StaxInEndingInterceptor.class.getName()); } public void handleMessage(Message message) throws Fault { message.getInterceptorChain().remove(StaxInEndingInterceptor.INSTANCE); } } public void initialize(Service service) { for (ServiceInfo serviceInfo : service.getServiceInfos()) { SchemaCollection schemaCollection = serviceInfo.getXmlSchemaCollection(); if (schemaCollection.getXmlSchemas().length > 1) { // Schemas are already populated. continue; } new ServiceModelVisitor(serviceInfo) { public void begin(MessagePartInfo part) { if (part.getTypeQName() != null || part.getElementQName() != null) { return; } part.setTypeQName(Constants.XSD_ANYTYPE); } }.walk(); } } @SuppressWarnings("unchecked") public <T> DataReader<T> createReader(Class<T> cls) { if (cls == XMLStreamReader.class) { return (DataReader<T>) xsrReader; } else { throw new UnsupportedOperationException( "The type " + cls.getName() + " is not supported."); } } public Class<?>[] getSupportedReaderFormats() { return new Class[] { XMLStreamReader.class }; } @SuppressWarnings("unchecked") public <T> DataWriter<T> createWriter(Class<T> cls) { if (cls == XMLStreamWriter.class) { return (DataWriter<T>) xswWriter; } else { throw new UnsupportedOperationException( "The type " + cls.getName() + " is not supported."); } } public Class<?>[] getSupportedWriterFormats() { return new Class[] { XMLStreamWriter.class, Node.class }; } public static class XMLStreamDataReader implements DataReader<XMLStreamReader> { public Object read(MessagePartInfo part, XMLStreamReader input) { return read(null, input, part.getTypeClass()); } public Object read(QName name, XMLStreamReader input, Class<?> type) { return input; } public Object read(XMLStreamReader reader) { return reader; } public void setSchema(Schema s) { } public void setAttachments(Collection<Attachment> attachments) { } public void setProperty(String prop, Object value) { } } public static class XMLStreamDataWriter implements DataWriter<XMLStreamWriter> { private static final Logger LOG = LogUtils .getL7dLogger(XMLStreamDataWriter.class); public void write(Object obj, MessagePartInfo part, XMLStreamWriter writer) { try { if (!doWrite(obj, writer)) { // WRITE YOUR LOGIC HOW you WANT TO HANDLE THE INPUT DATA //BELOW CODE JUST CALLS toString() METHOD if (part.isElement()) { QName element = part.getElementQName(); writer.writeStartElement(element.getNamespaceURI(), element.getLocalPart()); if (obj != null) { writer.writeCharacters(obj.toString()); } writer.writeEndElement(); } } } catch (XMLStreamException e) { throw new Fault("COULD_NOT_READ_XML_STREAM", LOG, e); } } public void write(Object obj, XMLStreamWriter writer) { try { if (!doWrite(obj, writer)) { throw new UnsupportedOperationException("Data types of " + obj.getClass() + " are not supported."); } } catch (XMLStreamException e) { throw new Fault("COULD_NOT_READ_XML_STREAM", LOG, e); } } private boolean doWrite(Object obj, XMLStreamWriter writer) throws XMLStreamException { if (obj instanceof XMLStreamReader) { XMLStreamReader xmlStreamReader = (XMLStreamReader) obj; StaxUtils.copy(xmlStreamReader, writer); xmlStreamReader.close(); return true; } else if (obj instanceof XMLStreamWriterCallback) { ((XMLStreamWriterCallback) obj).write(writer); return true; } return false; } public void setSchema(Schema s) { } public void setAttachments(Collection<Attachment> attachments) { } public void setProperty(String key, Object value) { } } }
-
准备好你的输入以匹配预期的输入,比如下面的
private Object[] prepareInput(BindingOperationInfo operInfo, String[] paramNames, String[] paramValues) { List<Object> inputs = new ArrayList<Object>(); List<MessagePartInfo> parts = operInfo.getInput().getMessageParts(); if (parts != null && parts.size() > 0) { for (MessagePartInfo partInfo : parts) { QName element = partInfo.getElementQName(); String localPart = element.getLocalPart(); // whatever your input data you need to match data value for given element // below code assumes names are paramNames variable and value in paramValues for (int i = 0; i < paramNames.length; i++) { if (paramNames[i].equals(localPart)) { inputs.add(findParamValue(paramNames, paramValues, localPart)); } } } } return inputs.toArray(); }
-
现在设置正确的数据绑定并传递数据
Bus bus = CXFBusFactory.getThreadDefaultBus(); WSDLServiceFactory sf = new WSDLServiceFactory(bus, wsdl); sf.setAllowElementRefs(false); Service svc = sf.create(); Client client = new ClientImpl(bus, svc, null, SimpleEndpointImplFactory.getSingleton()); StaxDataBinding databinding = new StaxDataBinding(); svc.setDataBinding(databinding); bus.getFeatures().add(new StaxDataBindingFeature()); BindingOperationInfo operInfo = ...//find the operation you need (see below) Object[] inputs = prepareInput(operInfo, paramNames, paramValues); client.invoke("operationname", inputs);
-
如果需要,你可以在下面匹配操作名称
private BindingOperationInfo findBindingOperation(Service service, String operationName) { for (ServiceInfo serviceInfo : service.getServiceInfos()) { Collection<BindingInfo> bindingInfos = serviceInfo.getBindings(); for (BindingInfo bindingInfo : bindingInfos) { Collection<BindingOperationInfo> operInfos = bindingInfo.getOperations(); for (BindingOperationInfo operInfo : operInfos) { if (operInfo.getName().getLocalPart().equals(operationName)) { if (operInfo.isUnwrappedCapable()) { return operInfo.getUnwrappedOperation(); } return operInfo; } } } } return null; }