1. 程式人生 > >使用CXF時服務端接收到的引數值為null

使用CXF時服務端接收到的引數值為null

環境說明:cxf的版本為cxf-2.1.4,spring版本為2.5

使用CXF來訪問webservice時,服務端接收到的引數值為null,以下兩種原因會造成這一狀況

(一)釋出方式和客戶端訪問代理方式不匹配
服務釋出的方式和客戶端訪問代理的方式不匹配就會出現呼叫不到服務或者能呼叫到服務但是接收到的引數值為NULL的情況。

一般使用simple或jax-ws的方式來發布
使用simple的方式來發布時,示例程式碼:

ClientProxyFactoryBean factory2 = new ClientProxyFactoryBean();
factory2.setServiceClass(Iwbjk.class);
factory2.setAddress("http://192.10.110.80:8080/NewFrame/services/Wbjk");
Iwbjk wx = (Iwbjk) factory2.create();
wx.sendMessageImmediately("222222222", "3333333333");

使用jax-ws的方式來發布,程式碼和上面一樣,把ClientProxyFactoryBean換成JaxWsProxyFactoryBean即可。
另外,有時候使用了simple的方式來發布服務,使用JaxWsProxyFactoryBean生成代理也是可以訪問的,但是需要你指定的介面類中必須使用了 @webservice 註解。雖然可以這麼做,但是不建議這麼做,用相匹配的方式來訪問webservice可以避免使用過程中發生詭異的問題。
更多代理訪問方法可以參考CXF官網http://cxf.apache.org/docs/frontends.html

(二)錯誤的服務釋出配置

錯誤的釋出配置也會導致接受到的引數值為null,比如servicename,endpointName屬性沒有按照要求的格式 ns:format

解決方法:
1)修改你的配置
  修改配置是最簡單的方法,但是如果是別人的系統不允許你修改配置,你還可以嘗試下面的方法。

2)如果你使用了錯誤的配置但是你不能改
嘗試使用qname,指定服務名稱空間後再呼叫

ClientProxyFactoryBean factory2 = new ClientProxyFactoryBean();
factory2.setServiceClass(Iwbjk.class);
QName qname = new QName("http://www.springframework.org/schema/beans","Wbjk");
factory2.setServiceName(qname);
factory2.setAddress("http://192.10.110.80:8080/NewFrame/services/Wbjk");
Iwbjk wx = (Iwbjk) factory2.create();
String res = wx.sendMessageImmediately("222222222", "3333333333");

QName構造器需要的兩個引數可以通過wsdl來知曉,見下圖中標紅的部分:


【附上一個詭異的問題】同樣錯誤的配置,為什麼有的可以訪問,有的不可以?
在釋出一個服務時使用了錯誤的配置,像下面的配置這樣,指定endpointName和serviceName時沒有按照官方要求的格式去做(ns:xxxxx)
由於配置錯誤導致訪問服務方法sendMessageImmediately時接收到的引數值總是為null,但是詭異的其它的webservice也是這樣配置的,卻沒有這樣的錯誤。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:simple="http://cxf.apache.org/simple"
	xmlns:soap="http://cxf.apache.org/bindings/soap"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd">

	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />


	<simple:server id="pojoservice"  serviceBean="#WbjkWS" serviceClass="com.wisoft.framework.ams.ws.Iwbjk"  
	               address="/Wbjk" endpointName="Wbjk" serviceName="Wbjk">
        </simple:server>
	<bean id="WbjkWS" class="com.wisoft.framework.ams.ws.WbjkWS"
		abstract="false" lazy-init="default" autowire="default" 
		dependency-check="default">
	</bean>
</beans>
另外附上這個服務類的介面
public  interface Iwbjk {
	public String sendMessageImmediately(String destNumber, String content);
}
,最後花了好長時間發現那些可以正常使用的服務類中方法有返回複雜物件型別的而Iwbjk中只有一個返回String的方法,難道是返回值的問題?改成下面這樣之後果然可以正常接收引數了。
public  interface Iwbjk {
	public BaseReturn sendMessageImmediately(String destNumber, String content);
}

那麼為什麼要有複雜物件型別引數才行?這個錯誤的問題還要不要繼續深究?
如果像上面這樣配置錯誤,我認為專案忙的情況下沒有必要深究,配置都錯了,錯誤的現象往往會多種多樣,你很難想的通,除非願意去看原始碼。
從解決問題的角度,這讓我們更加豐富了“比較法”的使用經驗,至少以後知道方法返回值型別也是一個需要關注的點。