詳談cxf和axis兩種框架下的webservice客戶端開發(fā)
客戶端相比服務(wù)端,基本沒啥配置。引入jar包就好。我這里為了看效果,是新建了maven工程來做客戶端。調(diào)用另一個webservice服務(wù)端maven工程.
環(huán)境:jdk1.7+maven3.3.9+tomcat7
框架:spring+cxf/spring+axis(這里不是axis2,是axis)
第一種:基于cxf的客戶端開發(fā)
1.引入依賴 pom.xml
這里把兩種框架的依賴一次到位。就不分開引入了。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zhanglf</groupId>
<artifactId>cxfClientTest</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>cxfClientTest Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- 添加 Spring dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- 添加CXF dependency -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.1.5</version>
</dependency>
<!-- 添加CXF dependency -->
<!-- 另一種axis方法調(diào)用webservice依賴 -->
<dependency>
<groupId>org.apache.axis</groupId>
<artifactId>axis</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.apache.axis</groupId>
<artifactId>axis-jaxrpc</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>axis</groupId>
<artifactId>axis-wsdl4j</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
<version>0.2</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- 另一種axis方法調(diào)用webservice -->
</dependencies>
<build>
<finalName>cxfClient</finalName>
</build>
</project>
2.cxf和axis都沒有spring配置
直接進(jìn)入業(yè)務(wù)代碼CxfClientTest.java
package com.zhanglf;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
public class CxfClientTest {
public static void main(String[] args) throws Exception {
JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
//通過wsdl服務(wù)描述文件創(chuàng)建客戶端工廠。
Client client = factory.createClient("http://localhost:8080/springCXFWebserviceDemo01/service/HelloWorldService?wsdl");
//嘗試使用不帶?wsdl的地址
//Client client = factory.createClient("http://localhost:8080/springCXFWebserviceDemo01/service/HelloWorldService");
//invoke(
//String operationName:要調(diào)用的方法名
//Object... params):方法的入?yún)ⅰ?梢允嵌鄠€。
Object[] objs = client.invoke("sayHello", "阿福");
//invoke方法是默認(rèn)返回Object[]數(shù)組。取出數(shù)組的第一位值得值就是返回值。
System.out.println(objs[0].toString());
}
}
直接Run As Java Application.可以看到在控制臺打出訪問服務(wù)端的代碼。

拓展:這里的客戶端只是傳了一個簡單的人名,正常傳入的是個String類型的xml報文。然后服務(wù)端接收報文,進(jìn)行報文解析,并對信息進(jìn)行crud操作。并將執(zhí)行結(jié)果以報文形式發(fā)送到客戶端。客戶端在進(jìn)行報文解析。判斷執(zhí)行情況以便進(jìn)行下一步操作。下面我們用axis框架進(jìn)行稍微接近業(yè)務(wù)的代碼開發(fā)。
axis客戶端代碼和cxf都在一個maven工程里。我把工程結(jié)構(gòu)貼出來供參考

第二種:基于axis框架的客戶端開發(fā)
AxisClientTest.java的code,所有涉及的點我都在代碼里說了。解釋的文字比較多,代碼并不多。
package com.zhanglf;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
/**
*
說明:address="http://localhost:8080/HelloWorld/services/user?wsdl"
* http://localhost:8080/HelloWorld:工程訪問路徑,
* /services:此路徑在web.xml里面配置cxf攔截器前置訪問路徑
* /user:此路徑在服務(wù)端的applicationContext.xml里配置的,要暴露給外部調(diào)用的接口,address:請求路徑
*
* @author Administrator
*
*/
public class AxisClientTest {
public static void main(String[] args) throws Exception {
// namespaceURI
// 為:一般可以認(rèn)為是<wsdl:definitions>中的targetNamespace的值,最好還是<wsdl:definitions>標(biāo)簽下的
// xmlns:tns的值為準(zhǔn)。
// 也是webservice接口的類上注解的targetNamespace,效果如同spring中的requestMapping,用來區(qū)分請求定位到具體的那個接口。
// 這里的命名空間對應(yīng)的是接口上面的targetNamespace,而不是實現(xiàn)類上面的。故通過wsdl中的<wsdl:definitions
// 里面的targetNamespace是不準(zhǔn)的,應(yīng)該以<wsdl:import 中的
// namespace為準(zhǔn)或者<wsdl:definitions>標(biāo)簽下的 xmlns:tns的值為準(zhǔn)
String nameSpaceURI = "com.serviceTargetName";
// 指出service所在URL,這個有沒有?wsdl均能正確訪問。。。,這里區(qū)別于cxf,cxf是不能少這個?wsdl
String publishUrl = "http://localhost:8080/springCXFWebserviceDemo01/service/HelloWorldService?wsdl";
// 創(chuàng)建一個服務(wù)(service)調(diào)用(call)
Service service = new Service();
// 通過service創(chuàng)建call對象
Call call = (Call) service.createCall();
// 設(shè)置webservice接口地址
call.setTargetEndpointAddress(new URL(publishUrl));
// 你需要遠(yuǎn)程調(diào)用的方法new QName(定位類的targetnamespace,定位方法的方法名)
/**
* call.setOperationName(new QName("serviceTargetName", "sayHello"));
* 方法中的QName方法的入?yún)⒄f明: new QName( String
* namespaceURI-定位接口的命名空間:接口注解targetnamespace的值或者wsdl文件
* <wsdl:definitions中的xmlns
* :tns="com.serviceTargetName"來鎖定targetnamespace的值, 這里不能用wsdl文件<wsdl:
* definitions中的targetNamespace來確定值的原因在于這里的值來源與接口實現(xiàn)類上的targetNamespace注解的值
* 。如果你接口的實現(xiàn)類中的targetNamespace和接口的不一樣,豈不是搞錯了。 String
* localPart-接口下定位方法的方法名
* :就是這里的抽象方法sayHello方法名,或者wsdl文件<wsdl:binding標(biāo)簽下<wsdl:operation
* name="sayHello"中name的值。 )
*/
call.setOperationName(new QName(nameSpaceURI, "sayHello"));
// 方法參數(shù),如果沒有參數(shù)請無視。這里如果接口沒有用@WebParam(name = "name"),則會報錯:Unmarshalling
// Error: 意外的元素 (uri:"", local:"name")。所需元素為<{}arg0>
call.addParameter("parameterName", XMLType.XSD_STRING, ParameterMode.IN);
// call.addParameter(new QName(soapaction,"xxxx"), XMLType.XSD_STRING,
// ParameterMode.IN);
// 設(shè)置返回類型,一般用string接收
call.setReturnType(XMLType.XSD_STRING);
// 給方法傳遞參數(shù),并且調(diào)用方法
String name = "zhanglifeng";
String temp = getXml(name);
// 這里的obj{}是放入幾個入?yún)?,完全由service提供的接口方法的入?yún)Q定,且順序和你存放的順序一致!一般入?yún)镾tring類型的xml報文,回參也是xml報文。
Object[] obj = new Object[] { temp };
String result = (String) call.invoke(obj);
System.out.println(result);
}
private static String getXml(String name) {
StringBuffer sb = new StringBuffer(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.append("<userBean>");
sb.append("<userName>" + name + "</userName>");
sb.append("</userBean>");
return sb.toString();
}
}
運行方法:Run As Java Application.客戶端的請求的入?yún)笪娜缦拢?/p>
<?xml version="1.0" encoding="UTF-8"?>
<userBean>
<userName>" + 入?yún)ⅲ喝嗣?+ </userName>
</userBean>
下面我把調(diào)用服務(wù)端的方法也貼出來,這樣更好理解。昨天已經(jīng)貼出了服務(wù)端的目錄結(jié)構(gòu),我就把其中的HelloWorldImpl.java中的sayHello方法改一下。code如下:
package com.zlf.impl;
import javax.jws.WebService;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import com.util.XMLUtils;
import com.zlf.HelloWorld;
/**
* 由于實現(xiàn)類和接口不在同一個包中。所以要加上targetNamespace屬性。
* 另外,這里的endpointInterface是實現(xiàn)類對應(yīng)接口的全路徑
* @author Administrator
*/
@WebService(targetNamespace="com.serviceTargetName",endpointInterface="com.zlf.HelloWorld")
@Component("HelloWord")//spring注入用
public class HelloWorldImpl implements HelloWorld {
@Override
public String sayHello(String str) {
String username="aaa";
Document document = XMLUtils.parse(str);
//首先接口開發(fā)肯定是雙發(fā)都知道此方法要接受的報文格式的。我們獲取報文中人名對應(yīng)的節(jié)點即可。
Node node = document.getElementsByTagName("userName").item(0);
if(node !=null){
username=node.getTextContent();
}
return "你好,"+username+" 你已成功訪問了webservice服務(wù)端!" ;
}
}
XMLUtils.java工具類我也貼出來,這個也比較常用。
package com.util;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* 解析器
* @author Administrator
*
*/
public class XMLUtils {
private final static DocumentBuilder createDocumentBuilder(){
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=null;
try {
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
builder=factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return builder;
}
public final static Document parse(InputSource in){
try {
return createDocumentBuilder().parse(in);
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public final static Document parse(String xml){
return parse(new InputSource(new StringReader(xml)));
}
}
這樣就完成了客戶端對服務(wù)端的調(diào)用。畢竟是初步入門。對以后的開發(fā)還是有所裨益。
一個客戶端和服務(wù)端底層傳輸數(shù)據(jù)的了解
客戶端傳入?yún)?shù),執(zhí)行String result = (String) call.invoke(new Object[] { “zhanglifeng”})后,實際發(fā)送給服務(wù)端的是一個soap底層協(xié)議自動生成的入?yún)笪摹?/p>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:com="com.serviceTargetName">
<soapenv:Header/>
<soapenv:Body>
<com:sayHello>
<!--Optional:-->
<parameterName>zhanglifeng</parameterName>
</com:sayHello>
</soapenv:Body>
</soapenv:Envelope>
服務(wù)端接收這個報文后自動解析,并把入?yún)①x值給方法sayHello(String str)的入?yún)tr.經(jīng)過處理數(shù)據(jù)返回給客戶端,也是soap底層自動生成的回參報文
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:sayHelloResponse xmlns:ns2="com.serviceTargetName">
<return>你好,zhanglifeng 你已成功訪問了webservice服務(wù)端!</return>
</ns2:sayHelloResponse>
</soap:Body>
</soap:Envelope>
客戶端自動把從返回報文中取出返回值,并付值給String result。這樣底層已經(jīng)處理過了報文。還有一種情況就是如果客戶端傳過來的參數(shù)本身就是xml時,底層封裝參數(shù)的問題。
如果客戶端的invoke()方法入?yún)?/p>
String xml=" <?xml version=\"1.0\" encoding=\"UTF-8\"?><userBean><userName>zhanglifeng</userName></userBean>"
底層自動為xml加上<![CDATA[ xml ]]>:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:com="com.serviceTargetName">
<soapenv:Header/>
<soapenv:Body>
<com:sayHello>
<!--Optional:-->
<parameterName><![CDATA[<?xml version="1.0" encoding="UTF-8"?><userBean><userName>zhanglifeng</userName></userBean> ]]></parameterName>
</com:sayHello>
</soapenv:Body>
</soapenv:Envelope>
知道這個原理,在使用SoupUI進(jìn)行調(diào)用webservice接口時就可以使用這種<![CDATA[ 入?yún)ml ]]>格式進(jìn)行調(diào)用。soupui調(diào)用的入?yún)⑷缦聢D

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用Maven打包時包含資源文件和源碼到j(luò)ar的方法
這篇文章主要介紹了使用Maven打包時包含資源文件和源碼到j(luò)ar的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
SpringCloud?Alibaba環(huán)境集成之nacos詳解
Spring?Cloud?Alibaba提供了越來越完善的各類微服務(wù)治理組件,比如分布式服務(wù)配置與注冊中心nacos,服務(wù)限流、熔斷組件sentinel等,本篇先來介紹SpringCloud?Alibaba環(huán)境集成之nacos詳解,需要的朋友可以參考下2023-03-03
詳解自動注冊Gateway網(wǎng)關(guān)路由配置
這篇文章主要為大家介紹了自動注冊Gateway網(wǎng)關(guān)路由配置的方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Spring mvc是如何實現(xiàn)與數(shù)據(jù)庫的前后端的連接操作的?
今天給大家?guī)淼氖顷P(guān)于Spring mvc的相關(guān)知識,文章圍繞著Spring mvc是如何實現(xiàn)與數(shù)據(jù)庫的前后端的連接操作的展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
java實現(xiàn)哈弗曼編碼與反編碼實例分享(哈弗曼算法)
本文介紹java實現(xiàn)哈弗曼編碼與反編碼實例,大家參考使用吧2014-01-01

