本类型文档适用于技术整理、网络转载、新技术介绍,有助于学习和提升
Web Service 应用
-- Axis1.4+tomcat5.5
Web Service 的定义
Web Service 是一个应用程序,是能够用编程的方法通过 Web 调用来实现某个功能的应用程序, Web Service 支持 Web 协议,如: HTTP,TCP/IP,SMTP 等 ,是基于 HTTP 协议的组件服务。
Web Service 的标准:
l XML 数据格式
l SOAP ( 简单对象访问协议 )
l WSDL(Web Service 描述语言 )
WSDD : 指 Web 服务描述文件( web service Deployment Descriptor )。
WSDL : 指网络服务描述语言 (Web Services Description Language) 。一种使用 XML 编写的文档。这种文档可描述某个 Web service 。
Axis 介绍
Axis ( Apache eXtensible Interaction System )是一款开源的 WebService 运行引擎,它是 SOAP 协议的一个实现。 Axis 分为 1.x 系列和 2 系列,两个系列体系结构和使用上有较大的区别,相对而言, Axis1.x 更加稳定,文档比较齐全。 Axis2 操作更加方便。
安装 axis1.4
1) 在 http://ws.apache.org/axis/ 上找到 AXIS 1.4 包,这里下载的是 axis-bin-1_4.zip 。解压 axis-bin-1_4.zip 这个包可以看到 webapps 目录,双击进入把里面的 AXIS 文件夹拷到 %TOMCAT_HOME%/webapps 目录下 。所需 Jar 包如下:
2) 启动 tomcat ,在浏览器输入 http://localhost:8080/axis/ 会看到如下界面,表示安装成功:
在 tomcat 中发布服务
u 即时发布
即时发布提供了一种非常简单发布方式,发布者只要有 Java 源代码(也就是 .java 文件),然后把其后缀名改成 .jws (也就是 java web service 的缩写)拷贝到 %TOMCAT_HOME%/webapps/axis 目录下即完成所有发布工作。以下是一个例子:
1) 编写服务端代码 CCService .java:
public class CCService {
public String getUserInfo(String userId){
String result ;
if ( "long" .equals(userId))
{
result = "welcome long !!!" ;
} else
{
result = "login failed ! !" ;
}
return result ;
}
public int getSum( int a , int b){
return a + b ;
}
}
注:利用即时发布的 java 类不能带包名,否则将导致发布失败。
2) 将 java 源文件的后缀名改为 .jws 。放在 %TOMCAT_HOME%/webapps/axis 目录下。启动 tomcat 服务器,在地址栏输入 http://localhost:8080/axis/CCService.jws 。看到 Click to see the WSDL 连接表示发布成功,点击进入可看到发布的 wsdl 。
u 定制发布
即时发布不能使用带包名的 java 类发布,这种有很大局限性。比起即时发布,定制发布有更大的灵活性,当然发布也就更繁琐更复杂。一般项目中都使用这种发布方式。定制发布需要自己编写一个 WSDD ( web service Deployment Descriptor : Web 服务描述文件)文件,其实就是一个 XML 描述文件。下面是一小例子可参考。
1) 编写服务端 java 类
package com.service;
public class CCServiceWSDD {
public String getUserInfo(String userId){
String result ;
if ( "long" .equals(userId))
{
result = "welcome long !!!" ;
} else
{
result = "login failed ! !" ;
}
return result ;
}
public int getSum( int a , int b){
return a + b ;
}
}
此类包含两个方法,说明可以发布两个服务。
2) 发布服务
Ø 把编译好的 class 文件放在 %TOMCAT_HOME%/webapps/axis/WEB-INF/classes 目录下,必须带上包。如 java 文件定义包为 package com.service 。则应将该 class 文件放在 ../classes/com/service/ 目录下。
Ø 编写 wsdd 文件
在 %TOMCAT_HOME%/webapps/axis/WEB-INF/ 目录下新建一个 deploy.wsdd 文件,编写格式如下:
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service scope="session" name="CCServiceTest" provider="java:RPC">
<parameter name="className" value="com.service.CCServiceWSDD"/>
<parameter name="allowedMethods" value="*"/>
<parameter name="scope" value="request"/>
</service>
</deployment>
注: service 标签中定义要发布的服务
Ø 设置变量 PATH
进入 windows 下的命令窗口,输入 cmd ,切换到 %TOMCATPATH%/webapps/axis/WEB-INF 目录。输入如下命令,设置 AXISPATH 和 AXISCLASSPATH 。
设置 AXISPATH
set axispath=$TOMCATPATH$/webapps/axis/WEB-INF
注: 这里设置的是 axis 的目录,不一定要在 tomcat 目录下。目的是设置环境变量。
设置 AXISCLASSPATH
set AXISCLASSPATH=%AXISPATH%/lib/axis.jar;%AXISPATH%/lib/axis-ant.jar;%AXISPATH%/lib/commons-discovery-0.2.jar;%AXISPATH%/lib/commons-logging-1.0.4.jar;%AXISPATH%/lib/jaxrpc.jar;%AXISPATH%/lib/log4j-1.2.8.jar;%AXISPATH%/lib/mail-1.4.jar;%AXISPATH%/lib/saaj.jar;%AXISPATH%/lib/wsdl4j-1.5.1.jar;%AXISPATH%/lib/xmlsec-1.4.1.jar;%AXISPATH%/lib/activation-1.1.jar
注: 在设置 axispath 时路径中不能有空格。
Ø 然后确认 tomcat 是否启动,如果未启动需要启动 tomcat 。
Ø
在 DOS 下转换目录到 %TOMCAT_HOME%/webapps/axis/WEB-INF ,命令:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd
后,会当前目录下生成 server-config.wsdd 文件。后续如果还要发布服务可直接在 server-config.wsdd 文件中添加 service 元素,重启服务即可。
Ø 重新启动 tomcat. 则服务端的类已正式发布。
Ø 在浏览器地址栏输入 http://localhost:8080/axis/services 可查看当前发布的服务。
编写客户端
² 直接调用服务
此方法手写比较复杂,在不包含复杂类型的返货值或参数时 ( 复杂类型的参数后面详细说明 ) ,可参照如下:
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class CCClient2 {
public static void main(String[] args){
try {
String url =
"http://localhost:8080/axis/services/CCServiceTest" ;
Service service = new Service() ;
Call call = (Call)service.createCall();
call.setTargetEndpointAddress(url) ;
call.setOperationName( new QName(url, "getUserInfo" )) ;
String result = (String)call.invoke( new Object[]{ "long" }) ;
System. out .println( "The getUserInfo result is : " + result);
call.setOperationName( new QName(url, "getSum" )) ;
Integer sum = (Integer) call.invoke( new Object[]{ new Integer(1), new Integer(2)});
System. out .println( "The getSum result is : " + sum);
} catch (ServiceException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
² 通过 wsdl2java 生成的类,调用服务。
首先保证发布服务成功,通过浏览器可看到发布的 wsdl 。通过生成的 wsdl 生成客户端 java 类。
1) 设置好环境变量,如:
set WSDLtool=E:/WebService/webserice/Axis_lib
set classpath=.;%WSDLtool%/lib/axis.jar;%WSDLtool%/lib/axis-ant.jar;%WSDLtool%/lib/saaj.jar;%WSDLtool%/lib/commons-discovery-0.2.jar;%WSDLtool%/lib/jaxrpc.jar;%WSDLtool%/lib/commons-logging-1.0.4.jar;%WSDLtool%/lib/wsdl4j-1.5.1.jar;%WSDLtool%/lib/activation-1.1.jar;%WSDLtool%/lib/mail-1.4.jar
2) 通过命令 java org.apache.axis.wsdl.WSDL2Java -D E:/WebService/webserice/wsdl/ccQuery.xml 生成客户端 java 类。
注:前两步为设置环境变量,如之前已经设置好,可以不用重复设置。 xml 文件为发布的 wsdl (通过保存为 xml 格式),需写全部路径。通过 WSDL2JAVA 命令会生成 4 个文件,两个接口和两个实现类。
3) 编写客户端调用服务
首先通过创建 ServiceLocator 对象,然后通过 ServiceLocator 获得 BindingStub 对象,通过 BindingStub 对象直接调用客户端方法。如格式如下:
import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
import localhost.axis.services.CCServiceTest.CCServiceTestSoapBindingStub ;
import localhost.axis.services.CCServiceTest.CCServiceWSDDServiceLocator;
public class CCClient {
public static void main(String[] args){
try {
CCServiceTestSoapBindingStub binding = (CCServiceTestSoapBindingStub ) new CCServiceWSDDServiceLocator()
.getCCServiceTest();
String result = binding.getUserInfo( "long" ) ;
int sum = binding.getSum(3, 4) ;
System. out .println( "result : " + result);
System. out .println( "The Sum is : " + sum);
} catch (ServiceException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
传递对象
上面的例子只适用传递参数为简单类型(如 String , Integer 等),对于自定义对象 Web Service 作了特殊处理。
² 服务端编写
只需在类中定义一个方法,方法的入参或出参为自定义对象即可。如:
1) 编写服务端 JavaBean :
import java.util.ArrayList;
import java.util.List;
public class UserInfo implements java.io.Serializable {
private java.lang.String userId ;
private java.lang.String userName ;
private List<String> list ;
public UserInfo(){
list = new ArrayList<String>();
list .add ( "001" );
list .add ( "002" );
}
public List<String> getList() {
return list ;
}
public void setList(List<String> list) {
this . list = list;
}
public java.lang.String getUserId() {
return userId ;
}
public void setUserId(java.lang.String userId) {
this . userId = userId;
}
public java.lang.String getUserName() {
return userName ;
}
public void setUserName(java.lang.String userName) {
this . userName = userName;
}
}
2) 编写服务端:
import com.bean.UserInfo;
public class ServiceOfObject {
/**
* getUserInfo
* @return Object
*/
public UserInfo getUserInfo(String userName) throws NumberFormatException {
List<String > list = new ArrayList<String >() ;
list.add( "long1" ) ;
list.add( "long2" ) ;
UserInfo userInfo = new UserInfo() ;
userInfo.setUserId( "001" ) ;
userInfo.setUserName(userName) ;
userInfo.setList(list) ;
return userInfo ;
}
}
² 配置 server-confing.wsdd 文件(服务定制描述文件)
在 wsdd 文件中添加 service 标签,编写格式如下:
<service scope="session" name="ServiceOfObect" provider="java:RPC">
<parameter name="className" value="com.service.ServiceOfObject"/>
<!-- 发布 webservice 方法, value="*" '*' 代表所有 , 如果不想发布所有的方法,可以在
value 中,每个方法用空格分开,如发布两个方法: value="getUserName getUser"
-->
<parameter name="allowedMethods" value="*"/>
<parameter name="scope" value="request"/>
<!-- 对象映射,一对象为参数或返回值 -->
<beanMapping languageSpecificType="java:com.bean.UserInfo"
qname="ns1:UserInfo" xmlns:ns1="com.bean" />
<!-- 类型映射,将对象进行序列化( out )和反序列化( in ) -->
<typeMapping languageSpecificType="java:com.bean.UserInfo"
qname="ns1:UserInfo" xmlns:ns1="com.bean"
deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"/>
<namespace>server.com</namespace>
</service>
² 编写客户端
直接通过地址调用:
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
import com.bean.UserInfo;
public class ClientOfObject {
public static void main(String[] args){
try {
String url =
"http://localhost:8088/axis/services/ServiceOfObect" ;
Service service = new Service() ;
Call call = (Call)service.createCall();
// 调用 getUserInfo 方法, re : String , rsp : UserInfo
//=====================================================
QName qn = new QName( "url" , "getUserInfo" );
// 注册序列化和反序列化类
call.registerTypeMapping(UserInfo.class , qn,
new BeanSerializerFactory(UserInfo.class , qn),
new BeanDeserializerFactory(UserInfo.class , qn));
// 设置返回类型
call.setReturnType(qn, UserInfo.class );
call.setOperationName(qn) ;
call.setTargetEndpointAddress( new URL(url)) ;
call.addParameter( "userInfo" , qn, javax.xml.rpc.ParameterMode. IN );
// 调用 getUserInfo 方法, re : String , rsp : UserInfo
Object[] obj = { "long" } ;
UserInfo userInfo = (UserInfo)call.invoke(obj) ;
System. out .println( "The getUserInfo result is : " + userInfo.getList().size());
} catch (ServiceException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
注:传递复杂的对象,在调用服务端方法是,必须设置返回类型,设置方法参见如上例子。如通过 WSDL2java 命令生成客户端,客户端编写方式不变,参见如上例子可实现。
Axis1.4 与应用结合
Axis1.4 与应用的结合其步骤和上面差不多,只不过在这里我们要把相应的 jar 包拷贝 我们工程的 WEB-INFO 的 lib 目录底下,并且修改工程下的 web.xml 文件,至少要增加以下信息:
<servlet>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>
org.apache.axis.transport.http.AxisServlet
</servlet-class>
</servlet>
<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>
部署完后,便可在此工程中发布服务。发布服务方式同上,只是工程名不同。