?转自:http://blog.csdn.net/stoneyang2005/archive/2009/02/26/3939117.aspx
如果多家供应商为一家用户做Web项目时,往往会用到WebService来进行数据的同步,比如用户同步。若远程调用后返回的值并不是字符串(内容是xml格式),而是供应商甲程序中的实体(如User对象),那么供应商乙若要调用供应商甲提供的WebService接口,可以:
1、? 将供应商甲的源代码,拷贝过来使用;
2、? 将供应商甲相关的源代码的class文件打成jar包,拷贝过来使用;
?
看似两种方式都可以,但是,由于供应商甲开发的目录结构很混乱以致于不方便找寻所有相关的源码或打成jar包;或你认为他们的目录结构很繁冗或你没有足够的时间和对方进行交流来部署自己的环境;或双方公司之间竞争激烈,网络不安全等因素不允许相互传送代码,或由于日后WebService公布的接口越多造成更多的同样的问题……
为了解决这个问题,可以使用XFire的Wsgen从动态的WSDL中生成客户端较为方便。
?
请下载ANT包供环境使用 :
ANT下载地址为http://www.apache.org/dist/ant/binaries/apache-ant-1.7.1-bin.zip
?
一、ANT的配置
1、下载apache-ant-1.7.1-bin.zip,并解压缩到某一目录,在环境变量中添加ANT_HOME,值为安装目录;
2、把%ANT_HOME%/bin;添加到path环境变量中,在命令行下运行 ant -version,若有输出,比如“Apache Ant version …… compiled on …… ”,则说明配置成功。
?
二、通过WSDL生成客户端
1、????? 新建一个Java工程,取名为XFireWsgen,向IDE中导入相关依赖的jar包, “http://blog.csdn.net/stoneyang2005/archive/2009/02/24/3931841.aspx”的“一、1”中有说明;
2、????? 如图1,创建相应的文件夹和xml文件
????
???? 图1
?
XFireWsgen: 创建xfire文件夹
XFireWsgen/xfire: 创建WsGen文件夹
XFireWsgen/xfire/WsGen:创建client文件夹、lib文件夹、build.xml文件
XFireWsgen/xfire/WsGen/client:存放的是生成的客户端代码,需在build.xml文件中进行配置
XFireWsgen/xfire/WsGen/lib:存放的是上面所述依赖的jar包,并且需在build.xml文件中进行配置
XFireWsgen/xfire/WsGen/build.xml 根据此文件,通过ANT出客户端
?
build.xml
?????? view plaincopy to clipboardprint?
<project name="XFire-WsGen" basedir="./WsGen" default="wsgen">?
?
???? <path id="classpathId">?
?
???????? <fileset file="${basedir}/lib/*.jar">?
?
????????????? <include name="*.jar"/>?
?
???????? </fileset>?
?
???? </path>?
?
???????
?
???? <target name="clean" description="Prepare for clean build">?
?
???????? <delete dir="${basedir}/client"/>?
?
???????? <mkdir dir="${basedir}/client"/>?
?
???? </target>?
?
???????
?
???? <taskdef classpathref="classpathId" name="wsgen" classname="org.codehaus.xfire.gen.WsGenTask"></taskdef>?
?
???
?
???? <target name="wsgen" depends="clean">?
?
???????? <taskdef name='WsGenTask' classname="org.codehaus.xfire.gen.WsGenTask" classpathref="classpathId"/>?
?
???????? <WsGenTask outputDirectory="${basedir}/client" wsdl="http://localhost:38088/xfireDemo/services/business?wsdl" package="myclient" overwrite="true"/>?
?
???? </target>?
?
</project>?
<project name="XFire-WsGen" basedir="./WsGen" default="wsgen">
???? <path id="classpathId">
???????? <fileset file="${basedir}/lib/*.jar">
????????????? <include name="*.jar"/>
???????? </fileset>
???? </path>
????
???? <target name="clean" description="Prepare for clean build">
???????? <delete dir="${basedir}/client"/>
???????? <mkdir dir="${basedir}/client"/>
???? </target>
????
???? <taskdef classpathref="classpathId" name="wsgen" classname="org.codehaus.xfire.gen.WsGenTask"></taskdef>
?
???? <target name="wsgen" depends="clean">
???????? <taskdef name='WsGenTask' classname="org.codehaus.xfire.gen.WsGenTask" classpathref="classpathId"/>
???????? <WsGenTask outputDirectory="${basedir}/client" wsdl="http://localhost:38088/xfireDemo/services/business?wsdl" package="myclient" overwrite="true"/>
???? </target>
</project>
?
?
其中,“${basedir}/lib/*.jar”的lib和 “${basedir}/client”的client,就是上面所说要配置的;“http://localhost:38088/xfireDemo/services/business?wsdl”就是供应商甲提供的WSDL的地址;“myclient”为客户端放置的包名。
?
3、????? 在浏览器输入wsdl(“http://localhost:38088/xfireDemo/services/business?wsdl”)保
证服务开启时,再使用ANT运行build.xml,可以从IDE中运行,刷新后client文件夹下将是生成的客户端代码,如图2所示
????
???? 图2
?
?
4、????? 拷贝client文件夹下的所有内容到 src目录下后并新建包 stoneyang.test和
Test.java类,如图3所示
???
??? 图3
?
Test为远程调用客户端,调用相关的接口:
Test.java
?view plaincopy to clipboardprint?
package stoneyang.test;??
?
import java.util.List;??
?
import javax.xml.bind.JAXBElement;??
?
import myclient.businessClient;??
import myclient.businessPortType;??
import stoneyang.bean.ArrayOfBook;??
import stoneyang.bean.Book;??
import stoneyang.businessi.ArrayOfString;??
import stoneyang.businessi.GetBookByNameResponse;??
import stoneyang.businessi.GetBooksByNames;??
?
public class Test {??
??? public static void main(String[] args){??
??????????
??????? businessClient rc = new businessClient();??
??????? businessPortType rpt = rc.getbusinessHttpPort();??
??????? //bean对象,集合产生的工厂??
??????? stoneyang.bean.ObjectFactory ofBookFactory = new stoneyang.bean.ObjectFactory();??
??????? //远程调用方法参数和返回值的工厂方法??
??????? stoneyang.businessi.ObjectFactory ofBusinessFactory = new stoneyang.businessi.ObjectFactory();??
??????????
??????? /*? 第一个注释?
??????????? QName qName = new QName("http://bean.stoneyang","year");?
??????????? JAXBElement<String> paramList = new JAXBElement<String>( qName,String.class,"1986");?
??????? */?
??????? //和下面的1行代码起到相同的作用,但是,下面的代码不需要再到Book.java或wsdl去找寻域名,成员变量名,显得更为方便??
??????? JAXBElement<String> yearJAXB = ofBookFactory.createBookYear("1986");??
??????????
??????? /*? 第二个分注释?
??????????? GetBookByNameResponse getBookByNameResult = ofBusinessFactory.createGetBookByNameResponse();??
??????????? getBookByNameResult.setOut(rpt.getBookByName("《小红帽》"));?
??????????? Book book = getBookByNameResult.getOut();?
?????????????
??????? */?
??????? //和下面的1行代码起到相同的作用,但是下面的代码更为简洁,而且Java返回结果只有一种(要么String,要么List,而不会返回String和List)??
??????? Book book = rpt.getBookByName("《小红帽》");??
??????????
??????? book.setYear(yearJAXB);??
??????? println(book);??
??????????
??????????
??????? /*? 第三个注释?
??????????? ArrayOfString bookNames = ofBusinessFactory.createArrayOfString();?
??????????? List<String> bookNameList = bookNames.getString();?
??????????? bookNameList.add("《社会心理学》");?
??????????? bookNameList.add("《心理学与生活》");?
??????????? ArrayOfBook books = rpt.getBooksByNames(bookNames);?
??????? */?
??????? //和下面的7行代码起到相同的作用,虽然下面的代码看起来比较复杂,但是根据面向对象,使对象集中设置参数,集中取出参数,更方便维护,比如getBooksByNames有10个参数,那么这里只需要用getBooksByNamesPrama对象来取getIn0(),getIn1()……等??
??????? GetBooksByNames getBooksByNamesPrama = ofBusinessFactory.createGetBooksByNames();??
??????? ArrayOfString bookNames = ofBusinessFactory.createArrayOfString();??
??????? List<String> bookNameList = bookNames.getString();??
??????? bookNameList.add("《社会心理学》");??
??????? bookNameList.add("《心理学与生活》");??
??????? getBooksByNamesPrama.setIn0(bookNames);??
??????? ArrayOfBook books = rpt.getBooksByNames(getBooksByNamesPrama.getIn0());//返回的结果可以和"第二个注释"一样,使用ofBusinessFactory.createGetBookByNameResponse()来创建返回结果??
??????????
??????? List<Book> listBook = books.getBook();??
??????? for( Book b: listBook ){??
??????????? println(b);??
??????? }??
??????? ArrayOfBook booksWithSpecialYear = rpt.getBooksWithSpecialYear(book);//这里的参数类型和返回结果也可以使用ofBusinessFactory来创建,和上面的创建方式一样,这里为了看起来简单就这样写了。???
??????? List<Book> bookListWithSpecialYear = booksWithSpecialYear.getBook();??
??????? for( Book b: bookListWithSpecialYear ){??
??????????? println(b);??
??????? }??
??? }??
??? public static void println(Book book){??
??????? String name = book.getName().getValue();??
??????? String author = book.getAuthor().getValue();??
??????? String year = book.getYear().getValue();??
??????? String price = book.getPrice().getValue();??
??????? StringBuilder builder = new StringBuilder();??
??????????
??????? if( name != null && !"".equals(name.trim())){??
??????????? builder.append( " 名称: "+name );??
??????? }??
??????? if( author != null && !"".equals(author.trim())){??
??????????? builder.append( " 作者: "+author );??
??????? }??
??????? if( year != null && !"".equals(year.trim())){??
??????????? builder.append( " 年份: "+year );??
??????? }??
??????? if( price != null && !"".equals(price.trim())){??
??????????? builder.append( " 价格: "+price );??
??????? }??
??????? System.out.println( builder.toString());??
??? }??
}?
package stoneyang.test;
import java.util.List;
import javax.xml.bind.JAXBElement;
import myclient.businessClient;
import myclient.businessPortType;
import stoneyang.bean.ArrayOfBook;
import stoneyang.bean.Book;
import stoneyang.businessi.ArrayOfString;
import stoneyang.businessi.GetBookByNameResponse;
import stoneyang.businessi.GetBooksByNames;
public class Test {
?public static void main(String[] args){
??
??businessClient rc = new businessClient();
??businessPortType rpt = rc.getbusinessHttpPort();
??//bean对象,集合产生的工厂
??stoneyang.bean.ObjectFactory ofBookFactory = new stoneyang.bean.ObjectFactory();
??//远程调用方法参数和返回值的工厂方法
??stoneyang.businessi.ObjectFactory ofBusinessFactory = new stoneyang.businessi.ObjectFactory();
??
??/*? 第一个注释
???QName qName = new QName("");
???JAXBElement<String> paramList = new JAXBElement<String>( qName,"1986");
??*/
??//和下面的1行代码起到相同的作用,但是,下面的代码不需要再到Book.java或wsdl去找寻域名,成员变量名,显得更为方便
??JAXBElement<String> yearJAXB = ofBookFactory.createBookYear("1986");
??
??/*?第二个分注释
?? ?GetBookByNameResponse getBookByNameResult = ofBusinessFactory.createGetBookByNameResponse();
???getBookByNameResult.setOut(rpt.getBookByName("《小红帽》"));
???Book book = getBookByNameResult.getOut();
?? ?
??*/
??//和下面的1行代码起到相同的作用,但是下面的代码更为简洁,而且Java返回结果只有一种(要么String,要么List,而不会返回String和List)
??Book book = rpt.getBookByName("《小红帽》");
??
??book.setYear(yearJAXB);
??println(book);
??
??
??/*? 第三个注释
?? ?ArrayOfString bookNames = ofBusinessFactory.createArrayOfString();
???List<String> bookNameList = bookNames.getString();
???bookNameList.add("《社会心理学》");
???bookNameList.add("《心理学与生活》");
???ArrayOfBook books = rpt.getBooksByNames(bookNames);
??*/
??//和下面的7行代码起到相同的作用,getIn1()……等
?? ?GetBooksByNames getBooksByNamesPrama = ofBusinessFactory.createGetBooksByNames();
??ArrayOfString bookNames = ofBusinessFactory.createArrayOfString();
??List<String> bookNameList = bookNames.getString();
??bookNameList.add("《社会心理学》");
??bookNameList.add("《心理学与生活》");
??getBooksByNamesPrama.setIn0(bookNames);
??ArrayOfBook books = rpt.getBooksByNames(getBooksByNamesPrama.getIn0());//返回的结果可以和"第二个注释"一样,使用ofBusinessFactory.createGetBookByNameResponse()来创建返回结果
??
??List<Book> listBook = books.getBook();
??for( Book b: listBook ){
???println(b);
??}
??ArrayOfBook booksWithSpecialYear = rpt.getBooksWithSpecialYear(book);//这里的参数类型和返回结果也可以使用ofBusinessFactory来创建,和上面的创建方式一样,这里为了看起来简单就这样写了。
??List<Book> bookListWithSpecialYear = booksWithSpecialYear.getBook();
??for( Book b: bookListWithSpecialYear ){
???println(b);
??}
?}
?public static void println(Book book){
??String name = book.getName().getValue();
??String author = book.getAuthor().getValue();
??String year = book.getYear().getValue();
??String price = book.getPrice().getValue();
??StringBuilder builder = new StringBuilder();
??
??if( name != null && !"".equals(name.trim())){
???builder.append( " 名称: "+name );
??}
??if( author != null && !"".equals(author.trim())){
???builder.append( " 作者: "+author );
??}
??if( year != null && !"".equals(year.trim())){
???builder.append( " 年份: "+year );
??}
??if( price != null && !"".equals(price.trim())){
???builder.append( " 价格: "+price );
??}
??System.out.println( builder.toString());
?}
}
?
?
三、远程调用
运行 stoneyang.test.Test.java 后得到结果:
名称: 《小红帽》 年份: 1986年
名称: 《社会心理学》
名称: 《心理学与生活》
名称: 《小红帽》翻印版 年份: 1986年
名称: 《小红帽》影音版 年份: 1986年
?
四、分析相关的包和类
?????? 见下图(和图3一样),包和类的结构十分清晰:
??????
?
??????? myclient包:远程调用的配置环境和调用方法
????????????? usinessClient:??????? 远程调用的配置信息
????????????? businessImpl:??????? 若远程调用方法不支持此操作,抛出异常。
????????????? businessPortType:远程调用的服务接口
??????? stoneyang.bean包:????? bean对象、bean集合、bean成员变量相关的自定义类型和工厂
????????????? ArrayOfBook:???? 自定义的bean集合
????????????? Book:????????????????? Bean类,这里的成员变量以JAXBElement封装,指定其成员变量的变量名,域名以及绑定的方式类型
????????????? ObjectFactory:??? 生成此bean相关的对象,集合和bean的成员变量,这样,不需要我们手动为成员变量设置域名和变量名,更简单(见Test.java中的“第一注释”)
????????????? package-info:?????? 以java标注的形式映射XML名称空间和元素的名称空间的限制
???????
?????? stoneyang.businessi包:生成接口调用方法的参数类型对象和返回类型对象
????????????? ArrayOfString:????? 生成字符串集合
????????????? GetBookByName:生成接口中getBookByName方法中参数封装后的类
????????????? GetBookByNameResponse:生成接口中getBookByName方法中返回结果封装后的类
?
???????? ……
?
???????? ObjectFactory:????? 生成接口调用方法的参数对象以及返回值对象
????????????? ……
?
?????? stoneyang.test包: 远程调用的测试的包
?????? Test.java:?????? 测试的类,里面有详细的解释。
?
?????? META-INF/xfire/services.xml:可部署服务应用的配置文件
???????
??????
?????? 有兴趣的朋友可以将此文对比“http://blog.csdn.net/stoneyang2005/archive/2009/02/24/3931841.aspx”来看,或许把超链接中的代码作为供应商甲的代码,似乎就更清晰一些了。
?
希望看到的朋友,哪点看不明白或者有错误之处,敬请指出,谢谢。
?
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/stoneyang2005/archive/2009/02/26/3939117.aspx