使用JAVA调用.net WebService的终极解决方案

发现自己总是闭门造车,总是疏于整理与总结。下决心改变自己,从每件小事做起吧。共勉

最近做WebServices 比较多,和各种企业联调弄得楼主焦头烂额。其中,最郁闷的,还是与.net平台的对接。

楼主本地系统是Axis2 ,分别与Axis,Axis2与.net的接口来对接。

刚一开始采用的方案是基于采用本地发布的wsdl作为标准,使用Axis2工具生成Stub客户端来调用各企业接口。楼主一开始想当然的认为既然是发布的服务,应该遵守SOA的规范,那么通过生成的客户端,理应可以各种接口各种调。结果,残酷的事实证明,这样是行不通的。在采取客户端,调用Axis的服务时,发现了很尴尬的问题。使用本地的Stub,调用失败。

本地生成jibx Stub客户端方法如下:

写道
wsdl2java -uri ECS_NAT_INF_DataRecv.wsdl -p tobacco.ecs.pub -d jibx -s -uw -o build\client

 

注:需要配置%JAVA_HOME%

生成的客户端是在 tobacco.ecs.pub 下。

将生成的Stub客户端拷到项目目录下,使用stub客户端调用对方的方法时,错误如下:

写道
org.apache.axis2.AxisFault: Missing required element {http://tobacco/ecs/pub}return
at tobacco.ecs.pub.ECS_NAT_INF_DataRecvECS_NAT_INF_DataRecvSOAP12Port_http1Stub.receive(ECS_NAT_INF_DataRecvECS_NAT_INF_DataRecvSOAP12Port_http1Stub.java:371)
at tobacco.ecs.pub.StubTest.testReceive(StubTest.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

 

 经过分析,这个悲催的事情是因为命名空间发生的问题,我们就努力的统一命名空间,结果还是失败。

因为项目周期问题,楼主并没有在这一个问题上纠结下去,努力完成需求才是我们想要的。于是便采用了更加通用的方法,采用RPCclient,用invokeBlocking来调用,这次顺利成功。

至此,楼主本以为大功告成,Axis2与Axis顺利调通,哪知道,真正悲催的事情总是发生在最后。

在与两家企业顺利对接后,真正的boss,.net开发的服务接口找上门来了。使用RPCclient确实不能满足了。通过使用httplook抓取soap消息中,发现了问题。(这里吐槽一下,httplook真是神器啊。。。虽说好用,但是装上后机器变慢,卸载了又不能上网。。怨念)这边服务调用的时候,发送的request请求参数没有对应的名称,发送的request的OMElement参数都是arg0 arg1之流,到了那边,人家根本就不认,对方的Action也需要跟在命名空间后- -

这下可把楼主惹毛了,已经对接两家了,难不成还能因为一个.net平台难倒了?在不懈的努力下,终于发现,stub客户端中,是有拼接OMElement的方法的!灵机一动,我就打算自己拼接OMElement。

最终实现的代码如下:

/**
	 * 根据传入的参数返回拼装好的 OMElement
	 * @param omMap
	 * @param nameSpace
	 * @param action
	 * @return
	 */
	public OMElement getOmElement(Map<String, String> omMap, String action) {
		SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();

		OMElement child;

		OMElement wrapper = factory.createOMElement(action, namespace, "");
		Set<String> lableSet = omMap.keySet();
		Iterator<String> it = lableSet.iterator();
		while(it.hasNext()){
			String lable = it.next();
			child = factory.createOMElement(lable, namespace, "");
			child.setText(omMap.get(lable));
			wrapper.addChild(child);
		}
		return wrapper;
	}
	
	public String invoke(String action,OMElement wrapper) throws AxisFault {
		RPCServiceClient rpcClient = new RPCServiceClient();
		Options options = rpcClient.getOptions();
		EndpointReference targetEPR = new EndpointReference(endpoint);
		options.setTo(targetEPR);
		options.setAction(namespace + "/" + action);
		// 解决.net 调用java 调用不通时使用
		// options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED,Boolean.FALSE);
		
		OMElement response = rpcClient.sendReceive(wrapper);
		Object[] objects = BeanUtil.deserialize(response, new Class[] { String.class }, new DefaultObjectSupplier());
	
		return objects[0].toString();
	}

其中,deserialize 是对response返回的消息进行反序列化,可以形成我们原来的返回消息格式

 经过三番五次的测试,.net和java纷纷落马~O~Ye~

楼主经验尚浅,说的肯定有很多不对或者不准确或者瞎掰的地方。只求将解决方案与大家共勉,希望大家不要吝啬,多提宝贵意见及问题。

猜你喜欢

转载自eishang.iteye.com/blog/1551557