使用cxf的wsdl2java調用外部webservice提供的wsdl的步驟,使用過程中的問題與注意事項也做了相關總結。
一、可用的請求wsdl的webservice路徑
伺服器提供一個外部可調用的webservice的wsdl路徑,在浏覽器中可直接反問道wsdl檔案,在soapUI中可測試每個請求的有效的路徑(該webservice是已釋出可工外部調用的有效請求)
二、下載下傳配置Apache CXF提供的生成Client的工具
1.下載下傳:
http://cxf.apache.org/download.html官網 下載下傳apache-cxf-3.0.10.zip(或者别的壓縮包,建議使用較新的工具包),将下載下傳到的zip解壓到本地某個檔案下,如我解壓到D盤的tool檔案夾下
2.配置環境變量:
将cxf所在路徑配置到環境變量中,如CXF_HOME=D:\tools\apache-cxf-3.0.10,在Path變量中添加;%CXF_HOME%\bin(講cxf的bin目錄配置到path中)。
運作cmd dos指令,輸入wsdl2java -v,輸出為wsdl2java - Apache CXF 3.0.10這種版本資訊表示安裝配置成功,否則則可能安裝失敗
三、使用wsdl2java的指令生成用戶端代碼
1,簡單使用指令生成代碼到某目錄下:
可在本地手動切換到需要生成代碼的目錄下,在路徑中輸入cmd回車即轉到該目錄下——》wsdl2java -p '包名' -encoding UTF-8 https://XXX.XX.XXXService?wsdl 回車即可生成
-p 生成代碼放置的包,指令中建議加上,友善直接放到項目目錄下,預設的包可能不符java包的命名規則(如可能生成以java、org等包)
-encoding 建議加上,不指定編碼可能導緻生成的檔案産生編碼沖突的錯誤而無法直接使用
-autoNameResolution當有兩個或者多個wsdl需要生成到同一個目錄下時,再次運作指令行需加入此參數,如果wsdl中有相似相同的方法名或者引用了相同名稱的類會提示“具有相同名稱 "XXXX" 的類/接口已在使用。請使用類定制設定來解決此沖突。”,無法正常生成,在wsdl2java的指令中加上這段标示,标示每個wsdl生成類時都會生成一個唯一的Number,讓同名的類也可生成。注意事項或出現ObjectFactory的錯誤時參考下面使用難點中的2即可解決。
四、使用難點
注意1:cxf所依賴的包比較坑爹,包引用的版本不對會出現非常多的問題
(ws的插件可以使用比較新的版本)
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3.1-b03</version>
<dependencies>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>webservices-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<configuration>
<sourceDestDir>${project.build.directory}/generated-sources/jaxws-wsimport</sourceDestDir>
<xnocompile>true</xnocompile>
<verbose>true</verbose>
<extension>true</extension>
<catalog>${basedir}/src/jax-ws-catalog.xml</catalog>
</configuration>
</plugin>
cxf的jar包依賴的版本如果出現問題會導緻各種奇怪的報錯:(因為cxf2.3.3所依賴的cxf-rt-frontend-jaxws、cxf-rt-transports-http-jetty都是2.2以上,如果這兩個包是2.1hi報錯)
<cxf.version>2.2.3</cxf.version>
<!--cxf -->
<!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf</artifactId>
<version>2.3.3</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- Jetty is needed if you're are not using the CXFServlet -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
jaxb-api使用的版本也不可過高
<!-- jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>:
注意2:ObjectFactory conflicts
生成多個wsdl文檔代碼時,-autoNameResolution解決ObjectFactory類名稱相同産生沖突時,會導緻生成的ObjectFactory中隻存在後執行生成指令的wsdl
的相關節點與方法,當再次調用之前生成的方法時,會報錯說XXX,XX.XXService?wsdl 無法調用的錯,簡單的解決方式是講之間生成的ObjectFactory的相關節
點與方法在被覆寫掉的ObjectFactory中粘貼一遍即可
參照解決方法:http://www.codeproject.com/Tips/145051/Apache-CXF-wsdl-java-Error
注意3:The lifecycle method [finalizeConfig] must not throw a checked exception
當想要在應用中調用service來完成相關邏輯,如果直接調用會報錯類似The lifecycle method [finalizeConfig] must not throw a checked exception的錯誤,是因為在依賴中加入了 <!-- Jetty is needed if you're are not using the CXFServlet -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
當使用main函數或者junit測試代碼時可以加上這段,但調用時不可加入這段依賴
問題參考:https://issues.apache.org/jira/browse/CXF-5483
注意4:javax.xml.ws.WebServiceException: Unsupported endpoint address的錯誤
解決方法是在service中加入endpoint的設定或者在port中設定Provider的endpoint參數
參見:http://tugdualgrall.blogspot.jp/2009/02/jax-ws-how-to-configure-service-end_17.html
注意5:...can`t create a instance of XXX
http://stackoverflow.com/questions/7415659/instantiationexception-during-jaxb-unmarshalling-abstract-base-class-with-xml
五、成功案例
通過三生成的service可直接調用(XXXservice的注解為@WebServiceClient,注釋中各種需要的參數都是已經生成的)
XXXService service=new XXXService(XXX.Service.WSDL_LOCATION);//WSDL_LOCATION是生成的類中已經指派的路徑http://XXX.XXX.XXService?wsdl
XXXPortType port=service.getXXXEndpoint();
//如果請求的wsdl有Bisic Authentication的認證,需要加下面這段
((BindingProvider) port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "username");
((BindingProvider) port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "password");
//然後直接調用port中的方法,即可拿到資料
port.getCaptcha().getImagePath().getValue();
---------------------案例中使用的是wso2提供的的webservice
wsdl:
https://ids-dev.zhishinet.com:9443/services/UserInformationRecoveryService?wsdl
https://ids-dev.zhishinet.com:9443/services/RemoteUserStoreManagerService?wsdl
使用者:admin
密碼:admin
忘記密碼:
getUserList("http://wso2.org/claims/mobile",18666666666,null)
有使用者名,驗證驗證碼
VerificationBean ver = user.verifyUser(userName, null);
VerificationBean ver2 = user.sendRecoveryNotification(userName, ver.key, "");
VerificationBean ver3 = user.verifyConfirmationCode(userName, ver2.notificationData.notificationCode, null);
VerificationBean ver4 = user.updatePassword(userName, ver3.key, password);
修改密碼:
updateCredential