ª 先从官网(http://xfire.codehaus.org/)下载需要的jar包和文档
ª 编写CalculatorService接口
ª
ª WebService一般都是由两部分来组成的,一般有一个接口,接口用是来公开服务的,服务的执行由接口的实现类,来实现的。
ª 编写CalculatorService接口
package com.test.service;
publicinterfaceCalculatorService {
/**
*加
*@parama加数
*@paramb 加数
*@return 和
*/
publicint add(int a, int b);
/**
*减
*@parama 被减数
*@paramb 减数
*@return 差
*/
publicint subtract(int a, int b);
/**
*乘
*@parama 因数
*@paramb 因数
*@return 积
*/
publicint multiply(int a, int b);
/**
*除
*@parama 被除数
*@paramb 除数
*@return 商
*/
publicint divide(int a, int b);
}
ª 编写web.xml文件,在web.xml文件中加入XFireServlet类的<servlet-mapping>,可以从下载的文档中实例中获得web.xml文件内容。
<?xmlversion="1.0"encoding="UTF-8"?>
<web-appversion="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>XFireServlet</servlet-name>
<display-name>XFire Servlet</display-name>
<servlet-class>
org.codehaus.xfire.transport.http.XFireConfigurableServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
</web-app>
ª 在目录下新建META-INF文件夹,在META-INF目录下新建services.xml文件,并编写services.xml
i. 编写services.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://xfire.codehaus.org/config/1.0">
<service>
<!--指定服务的名称 -->
<name>CalculatorService</name>
<!--指定服务的接口 -->
<serviceClass>com.test.service.CalculatorService</serviceClass>
<!--指定接口的实现类 -->
<implementationClass>
com.test.service.impl.CalculatorServiceImpl
</implementationClass>
</service>
</beans>
ª 当服务器启动的时候,会加载web.xml中的配置信息,读取XfireConfigurableServlet,然后会将CalculatorService以服务(wsdl)的形式发布出去。
3.> Xfire-添加所需要的jar
ª 添加所需要的jar,添加lib上当下所有的jar,和xfire-all-1.2.6.jar,其中lib目录下的jar包是所依赖的jar。
ª
ª wsdl全称为:Web Service Description Language,wsdl是XML,公开服务越多,wsdl就越多。
ª 部署项目运行,以下图为例运行项目。
ª 根据web.xml文件中的配置,打开IE浏览器,在地址输入,http://localhost:8080/myxfire/services,显示:
<?xmlversion="1.0" encoding="UTF-8" ?>
-<wsdl:definitions targetNamespace="http://service.test.com" xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:tns="http://service.test.com" xmlns:wsdl=http://schemas.xmlsoap.org/wsdl/"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/"xmlns:soap12="http://www.w3.org/2003/05/soap-envelope>
-<wsdl:types>
-<xsd:schemaxmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://service.test.com">
-<xsd:element name="subtract">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="in0" type="xsd:int" />
<xsd:elementmaxOccurs="1" minOccurs="1" name="in1" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-<xsd:element name="subtractResponse">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="out" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-<xsd:element name="multiply">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="in0" type="xsd:int" />
<xsd:elementmaxOccurs="1" minOccurs="1" name="in1" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-<xsd:element name="multiplyResponse">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="out" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-<xsd:element name="divide">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="in0" type="xsd:int" />
<xsd:elementmaxOccurs="1" minOccurs="1" name="in1" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-<xsd:element name="divideResponse">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="out" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-<xsd:element name="add">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="in0" type="xsd:int" />
<xsd:elementmaxOccurs="1" minOccurs="1" name="in1" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-<xsd:element name="addResponse">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="out" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
-<wsdl:message name="divideRequest">
<wsdl:partname="parameters" element="tns:divide" />
</wsdl:message>
-<wsdl:message name="multiplyResponse">
<wsdl:partname="parameters" element="tns:multiplyResponse" />
</wsdl:message>
-<wsdl:message name="multiplyRequest">
<wsdl:partname="parameters" element="tns:multiply" />
</wsdl:message>
-<wsdl:message name="addResponse">
<wsdl:partname="parameters" element="tns:addResponse" />
</wsdl:message>
-<wsdl:message name="subtractRequest">
<wsdl:partname="parameters" element="tns:subtract" />
</wsdl:message>
-<wsdl:message name="divideResponse">
<wsdl:partname="parameters" element="tns:divideResponse" />
</wsdl:message>
-<wsdl:message name="subtractResponse">
<wsdl:partname="parameters" element="tns:subtractResponse" />
</wsdl:message>
-<wsdl:message name="addRequest">
<wsdl:partname="parameters" element="tns:add" />
</wsdl:message>
-<wsdl:portType name="CalculatorServicePortType">
-<wsdl:operation name="subtract">
<wsdl:inputname="subtractRequest" message="tns:subtractRequest" />
<wsdl:outputname="subtractResponse" message="tns:subtractResponse" />
</wsdl:operation>
-<wsdl:operation name="multiply">
<wsdl:inputname="multiplyRequest" message="tns:multiplyRequest" />
<wsdl:outputname="multiplyResponse" message="tns:multiplyResponse" />
</wsdl:operation>
-<wsdl:operation name="divide">
<wsdl:inputname="divideRequest" message="tns:divideRequest" />
<wsdl:outputname="divideResponse" message="tns:divideResponse" />
</wsdl:operation>
-<wsdl:operation name="add">
<wsdl:inputname="addRequest" message="tns:addRequest" />
<wsdl:outputname="addResponse" message="tns:addResponse" />
</wsdl:operation>
</wsdl:portType>
-<wsdl:binding name="CalculatorServiceHttpBinding" type="tns:CalculatorServicePortType">
<wsdlsoap:bindingstyle="document" transport="http://schemas.xmlsoap.org/soap/http" />
-<wsdl:operation name="subtract">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="subtractRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="subtractResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
-<wsdl:operation name="multiply">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="multiplyRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="multiplyResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
-<wsdl:operation name="divide">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="divideRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="divideResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
-<wsdl:operation name="add">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="addRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="addResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
-<wsdl:service name="CalculatorService">
-<wsdl:port name="CalculatorServiceHttpPort" binding="tns:CalculatorServiceHttpBinding">
<wsdlsoap:addresslocation="http://localhost:8080/myxfire/services/CalculatorService" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
i. 头部的网站都是固定的,除xmlns:tns="http://service.test.com"是根据包名反转生成的。
ii. <wsdl:message name="divideRequest">消息,服务器端收到消息后,进行处理,向客户端返回一个消息,请求结束。一共4个方法,8个消息。
iii. service最重要的是:
<wsdlsoap:address lcation="http://localhost:8080/myxfire/services/CalculatorService"/>指定了服务的地址。
iv. 对于元素来说都是严格,上面的依然下面的,例如:
1. 请求:
-<xsd:element name="subtract">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="in0" type="xsd:int" />
<xsd:elementmaxOccurs="1" minOccurs="1" name="in1" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
定义了两个元素,类型为int类型,最多出显1次,最少出现1次。
2. 响应:
-<xsd:element name="subtractResponse">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1" minOccurs="1" name="out" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
定义了一个元素,类型为int类型,最多出显1次,最少出现1次。
ª 从上面的例子中可以看出,将方法的参数做了一复杂类型,将方法的返回值做了一个复杂类型:
<wsdl:message name="subtractRequest">
l:partname="parameters" element="tns:subtract" />
</wsdl:message>
i. 当从服务器端发出请求,符合tns:subtract元素的xml对象,处理请求完之后,会向客户端返回一个符合subtractResponse元素的xml对象
-<xsd:element name="subtractResponse">
-<xsd:complexType>
-<xsd:sequence>
<xsd:elementmaxOccurs="1"minOccurs="1" name="out" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
ª portType定义了具体的方法,每一个operation代表了一个方法。调用方法时,会输入一个消息,当方法回来时候又返回来一个消息。每一个operation里面,有两个元素:input和output,input表示调用方法时候,传递一个tns:subtractRequest消息,output表示调用方法时候,传回一个tns:subtractResponse消息。
-<wsdl:portType name="CalculatorServicePortType">
-<wsdl:operation name="subtract">
<wsdl:inputname="subtractRequest" message="tns:subtractRequest" />
<wsdl:outputname="subtractResponse" message="tns:subtractResponse" />
</wsdl:operation>
-<wsdl:operation name="multiply">
<wsdl:inputname="multiplyRequest" message="tns:multiplyRequest" />
<wsdl:outputname="multiplyResponse" message="tns:multiplyResponse" />
</wsdl:operation>
-<wsdl:operation name="divide">
<wsdl:inputname="divideRequest" message="tns:divideRequest" />
<wsdl:outputname="divideResponse" message="tns:divideResponse" />
</wsdl:operation>
-<wsdl:operation name="add">
<wsdl:inputname="addRequest" message="tns:addRequest" />
<wsdl:outputname="addResponse" message="tns:addResponse" />
</wsdl:operation>
</wsdl:portType>
ª 依赖:
-<wsdl:binding name="CalculatorServiceHttpBinding" type="tns:CalculatorServicePortType">
<wsdlsoap:bindingstyle="document" transport="http://schemas.xmlsoap.org/soap/http" />
-<wsdl:operation name="subtract">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="subtractRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="subtractResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
-<wsdl:operation name="multiply">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="multiplyRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="multiplyResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
-<wsdl:operation name="divide">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="divideRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="divideResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
-<wsdl:operation name="add">
<wsdlsoap:operationsoapAction="" />
-<wsdl:input name="addRequest">
<wsdlsoap:bodyuse="literal" />
</wsdl:input>
-<wsdl:output name="addResponse">
<wsdlsoap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
-<wsdl:service name="CalculatorService">
-<wsdl:port name="CalculatorServiceHttpPort" binding="tns:CalculatorServiceHttpBinding">
<wsdlsoap:addresslocation="http://localhost:8080/myxfire/services/CalculatorService" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Service使用Binding,Binding使用ProtType, ProtType使用message, message使用自己定义的type。
5.> 新建(java Web)项目
ª Xfire提供了Ant(自动构建)实现在客户端实现在远程调用,先从官网(http://xfire.codehaus.org/Download)
i. Client and Server StubGeneration from WSDL:从wsdl里面产生服务端与客户端的Stub
ii. Stub:所谓的Stub,像一个代理,由本地的代理远程的一个接口。
iii. Xfire官方提供的示例:<taskdef>定义一个任务,<wsgen>使用任务。
ª 在项目实现自动构建(Ant)
i. 在项目根路径下新建build.properties
#生成的目录 basedir引用的build.xml中的basedir
src.dir=${basedir}/src
#源代码的目录
lib.dir=E:/Work/xfire-1.2.6/lib/
#指定wsdl的路径
wsdl.dir=http://localhost:8080/myxfire/services/CalculatorService?wsdl
ii. 在项目根路径下新建build.xml
<?xml version="1.0"encoding="UTF-8"?>
<!--定义project的名称, basedir定义为当前目录-->
<projectname="WebService"basedir="."default="gen-webservice">
<!--导入properties文件导入 -->
<propertyfile="build.properties"></property>
<!--指定jar包所在的位置-->
<pathid="project-classpath">
<!--fileset指文件包文件 lib.dir是在properties中定义的-->
<filesetdir="${lib.dir}">
<!--包含所有的以.jar文件-->
<includename="**/*.jar"/>
</fileset>
</path>
<targetname="gen-webservice">
<taskedname="wsgen"classname="org.codehaus.xfire.gen.WsGenTask"classpathref="project-classpath"/>
<wsgenoutputDirectory="${src.dir}"wsdl="${wsdl.dir}"package="com.xfire.client"overwrite="true"/>
</target>
</project>
iii. 运行后的效果如图:
ª 分析客户端代码
i. com.xfire.client.CalculatorServiceClient.java文件
iii. 图中画红线的地址为:访问远程服务器的地址,类中其它代码暂时先不去考虑。
iv. 打开CalculatorServicePortType接口,可以看到定义的方法,可以看作远程服务器的方法在客户的上面的Stub,客户端尝试接口里面的方法,就可以了,在底层会将调口访问的过程发送给服务端,由服务端进行处理。
ª 写测试类进行测试
i. 代码:
publicstaticvoid main(String[] args) {
//构造方法会完成本地Stub创建,以及服务器之间的链接
CalculatorServiceClient client =new CalculatorServiceClient();
// CalculatorService代理对象
CalculatorServicePortType portType = client.
getCalculatorServiceHttpPort();
intaddResult = portType.add(1, 2);
System.out.println("addResult===>" + addResult);
}
输出结果:addResult===>3
i. 在WebService服务器和客户机之间会传递SOAP消息,有时我们需要得到这些消息以便调试,而Apache的TCPMon可以帮助我们做到这一点。
ii. TCPMon的下载地址在http://download.csdn.net/detail/yuan_xw/4444457,双击tcpmon.jar就可以执行程序了。
iii. 这里有必要对tcpmon说明一下,它实际上是个代理,起一个消息转发的作用,监视的是转发出去的消息。最终,消息还是要送到具体的地址和端口,否则响应就不正确了。也就是说,TCPMon是一个消息的二传手,它的前后都应该配置正确才行。
iv. 请求原理示意图:
v. 双击tcpmon.jar启动后,
1. LocalPort:本地端口
2. Service Name:服务器的名字
3. SSL Service:服务端的端口
vi. 配置如图所示:
vii. 需要将刚才CalculatorServiceClient类中的构造方法中http://localhost:8080/myxfire/services/CalculatorService
修改URL地址端号为8080:http://localhost:5555/myxfire/services/CalculatorService
viii. 当我们再次运行程序时,请求的xml就出现
ix. 对于soap消息来说有两种,
1. Envelope信封
2. 真正的主要内容是在<soap:Body></soap:Body>之间
x. 上半部分是客户端请求,下半部分是服务器应响。
ª Web Service的压力测试,压力测试工具——JMeter
i. JMeter下载地址:http://jmeter.apache.org/download_jmeter.cgi
ii. 先执行jmeter.bat,再运行ApacheJMeter.jar
ª ApacheJMeter操作
i. 第一步:修改测试计划的名称:testplan
ii. 第二步:添加线程组,一个线程代表者一个用户
iii. 第三步:线程组参数配置
1. 线程数:10 表示:模拟10个用户
2. 循环次数:
a) 永远:不停的地访问
b) 指定具体如数字:10 每个线程执行10次
3. Ramp-Up Period(in seconds):间隔时间:
a) 10 表示,第一个线程和第二线程之间的间隔几秒钟,间隔总时间。
iv. 第四步:设置Sampler(采样器)
1. 添加Sampler
v. 第五步:设置SOAP/XML-RPCRequest参数
a) URL:表示远程webService的服务器地址
b) Soap/XML-RPC Data:表示每次请求访问的数据(数据从TCPMon中复XML请求数据即可)。
c) 文件名:将执行的结果返回到一个文件里面
ª 修改服务器端代码,添加显示报表,测试运行
打开com.test.service.impl.CalculatorServiceImpl类,请求的Soap/XML-RPC Data中请求的是服务器端的服务方法,修改服务器端的add方法,测试是否被调用。
i. 代码所示:
publicclassCalculatorServiceImplimplements CalculatorService {
privateintindex = 0;
publicint add(int a, int b) {
++index;
System.out.println("add invoked:" +index);
return a + b;
}
忽略剩余代码……
ii. 添加显示报表,如下图:
依次添加图形结果、用表格查看结果、查看结果树。
iii. 先保存,点击菜单栏上的“启动”,可以在服务器端的控制台,看到调用执行的结果,如图:
1. Tomcat执行结果:
根据参数设置add方法会被执行100次。
2. ApacheJMeter执行结果图:
图标如果是绿色的表示请求是成功的。
3. Web Service需要注意:
a) 在WebService里面,一种方法经常会有多个操作,与传统在项目用直接调用方法不同,是一种粗粒度的,远程调用服务器一个方法,方法尽量把客户在一次请求所要做的业务处理全部完成,而不希望客户端完成一次业务处理,去掉N次。
b) WebService会存在性能的问题。
c) 在项目开发里面,使用ApacheJMeter比较常用,有时间可以研究。
学习WebService推荐的书籍:
《Web_Service开发指南_2_1_.4》
——厚积薄发(yuanxw)