实战Webservice (axis)。
一、 webservice简介
webservice 的概念是使用一个标准的输出接口来定义代码提供的功能,以便让外界可以通过这个标准的输出接口来调用,而所谓的标准输出接口就是wsdl。通过webservice,可以实现不同系统间的交互功能, 比如,我们可以在esp里调用vsb里的站点数据与功能,甚至可以操作CS架构的系统。
限于篇幅,关于webservice更深一步的概念、理论、应用场景等内容请自行查找资料研究,我们在这里只讲如何快速地给webapp增加web服务的能力。
二、Axis环境的搭建
Axis框架来自 Apache 开放源代码组织,它是基于JAVA语言的最新的 SOAP 规范的开放源代码实现,它为java应用服务器提供了标准的webservice能力。
1. 下载Axis并解压
我们可以从 http://ws.apache.org/axis/index.html下载它的开发包。
2. 加入所需lib
将axis/webapps/axis/WEB-INF/lib/目录下的jar文件复制到自己的WEB-INF/lib目录下。应包括以下jar文件:
axis.jar, axis-ant.jar, axis-schema.jar, commons-discovery-0.2.jar,
commons-logging-1.0.4.jar, jaxrpc.jar, log4j-1.2.8.jar, saaj.jar,wsdl4j-1.5.1.jar
3. 修改web.xml
在WEB-INF/web.xml文件里增加以下内容
a) Servelet部分加入:
<servlet><servlet-name>AxisServlet</servlet-name> <display-name>Apache-Axis Servlet</display-name>
<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class></servlet> <servlet><servlet-name>AdminServlet</servlet-name><display-name>Axis Admin Servlet</display-name>
<servlet-class>org.apache.axis.transport.http.AdminServlet</servlet-class>
<load-on-startup>100</load-on-startup></servlet>
b) servlet-mapping部分加入
<servlet-mapping><servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern></servlet-mapping>
<servlet-mapping><servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern></servlet-mapping>
<servlet-mapping><servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern></servlet-mapping>
c) 还有listener
<listener><listener-class>org.apache.axis.transport.http.AxisHTTPSessionListener</listener-class></listener>
d) 最后再加入mime设定
<mime-mapping><extension>wsdl</extension>
<mime-type>text/xml</mime-type></mime-mapping>
<mime-mapping><extension>xsd</extension>
<mime-type>text/xml</mime-type></mime-mapping>
4. 在WEB-INF下增加server-config.wsdd文件
如果我们不使用jws(java文件后缀改为jws)文件而是使用class文件进行webservice服务端的部署,就需要在在WEB应用程序服务端的WEB-INF/目录下部署一个名字为server-config.wsdd的xml文件。每部署一个新的WEB服务时,都需要将新服务的描述信息加入到server-config.wsdd中。
如果将server-config.wsdd与WEB应用描述文件web.xml一并放置在WEB-INF目录下, Web服务器启动时,就会自动加载WEB服务。
当每增加一个新服务时,就需要在server-config.wsdd增加一个service,service主要是由各类型的parameter元素组成,通过parameter可以对类中允许访问的方法和需要传递非基本类型的方法的参数类型进行注册。
如果方法中传递非基本类型时需要提供对类型的序列化方法,需要使用BeanMapping、typeMapping等指定对这些非基本类型提供序列化和反序列化的类,在后面的附件传输中将进行介绍。
下面给出最简洁的server-config.wsdd文件内容:
<?xml version=”1.0″ encoding=”UTF-8″?>
<deployment xmlns:java=”http://xml.apache.org/axis/wsdd/providers/java”
xmlns=”http://xml.apache.org/axis/wsdd/” xmlns:ns1=”CmsServer”>
<handler type=”java:org.apache.axis.handlers.http.URLMapper” name=”URLMapper”/>
<!–service name=”StringUtil” provider=”java:RPC”>
<parameter name=”allowedMethods” value=”*”/>
<parameter name=”className” value=”webber.core.StringUtil”/>
</service–><!–sample: service定义的例子–>
<transport name=”http”><requestFlow><handler type=”URLMapper”/></requestFlow>
</transport></deployment>
Service部分只需要修改name(服务名)与parameter中className的value(具体提供服务的类)即可
三、实例
最简单的HelloWorld程序:
package sample;
public class HelloWorld {
public String sayHello(String name) {
return name + “HELLO WORLD!”;
}
}
编译后放入 WEB-INFclasses下的类路径里,然后在server-config.wsdd增加相应的描述
<service name=”HelloWorld ” provider=”java:RPC”><parameter name=”allowedMethods” value=” * ” />
<parameter name=”className” value=”sample. HelloWorld” /></service>
这样,webservice的服务端就搞定了!
我们可以写个客户端试验一下,TestClient.java:
import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.rpc.ParameterMode; public class TestClient { public static void main(String [] args)
throws Exception
{
String endpoint = “http://localhost:8080/system/services/HelloWorld “; // 指明服务所在位置, system是webapp名,根据需要换成你自己的webapp Service service = new Service(); //创建一个Service实例,注意是必须的! Call call = (Call) service.createCall(); //创建Call实例,也是必须的! call.setTargetEndpointAddress(endpoint); //为Call设置服务的位置 call.setOperationName( ” sayHello ” ); //要调用HelloWorld 中的方法名 String res = (String) call.invoke( new Object[] {“chen”} );//传入的参数需要封装到object数组中,返回值可直接获取 System.out.println( res ); //打印输出结果
}
}
在开发工具里执行这个类,你就能得到你想要的结果
四、进阶使用
1) 传递参数的类型
建议传递的参数限定到一些标准的类型中以增强兼容性,如int等基本数据类型,还有String、Hashtable等;如果你把自己编写的类作为参数传递,就必须对自己的类进行序列化处理,而且可能会导致你的webservice只能由java编写的客户端进行调用。
2) Session的使用,有状态的webservice
上面我们讲的是单个的方法调用;如果你想进行一系列有关联的调用,并且在调用的过程中想要保持一些变量,可以考虑使用webservice提供的session机制:
客户端只要保证以下几点即可
a. 调用service.setMaintainSession(true);
b. 保持这个service,也即是说,后续操作使用同一个service进行即可
服务端对session的处理采用以下方法:
MessageContext mc = MessageContext.getCurrentContext();
Session session = mc.getSession();
得到Session后可进行set与get,内容在session有效期间一直保持,原理与jsp中的session类似。
3)附件传输
附件的传输我们可以借助于DataHandler,而DataHandler属于非基本类型,因此我们首先要在server-config中用typemapping指定一个用于附件序列化和反序列化的类。具体如下:
<typeMapping deserializer=”org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory”
languageSpecificType=”java:javax.activation.DataHandler” qname=”ns1:DataHandler”
serializer=”org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory”
encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”/>
这样我们就可以在operation中用定义qname定义这种类型了,在客户端只要对该类型进行注册,我们就可以进行文件的传输了。进一步的操作,可以自行查阅相关文档。 值得注意的是,在文件传输的同时如果还要传输其他的类型要注意服务端和客户端的同步的问题。org.apache.axis.encoding.ser这个包中对很多类型都提供了序列化和反序列化的生成器,在传输其他的复杂类型时,我们都可以借助这个包里的工具。