运行环境:jdk1.5.0_11 + Tomcat5.5 + XFire-1.2.6
编译工具:MyEclipse 5.5.1 GA ( + Eclipse 3.2.2)
操作系统:Wiindows XP 番茄花园版
概述:利用xfire生成web服务客户端的方法有多种,Eclipse Plugin为XFire的WSDL->Code generator提供了Eclipse支持,它需要Eclipse 3.2和Java 5。这里我们用Eclipse Plugin根据wsdl文件地址生成客户端代码,而我们只需要编写几行代码即可实现调用web服务。
一、安装XFire插件
打开MyEclipse中的Help----->”Software Updates”----->”Find and Install.”----->"Search for new features to install",然后点击Next,
点击"New Remote Site...", 在Name中输入“XFire1.2.6”,在URL中输入“http://dist.codehaus.org/xfire/update/”后,点击“OK” ,点击Finish。
注意完成上述操作后,eclipse要下载和安装插件,时间长短要视网速而定,请耐心等待,安装完成时还要重启eclipse。
二、编写服务端
1、创建服务端项目
打开MyEclipse中File----->New---->Project,选择Web Service Project,点击Next,Project Name为Web_Server,点击Next,保持默认设置不变,继续点击Next,在Project Library Configuration(Add MyEclipse XFire and User libraries to project)界面里,选择相应的Libraries。勾选了Xfire1.2 Core Libraries、HTTP Client Libraries、XML Beans Libraries ,点击“Finish”完成了项目创建。目录结构如下所示:
Web_Server
src
JRE System Library
J2EE 1.4 Libraries
XFire 1.2 Core Libraries
XFire 1.2 HTTP Client Libraries
XFire 1.2 XML Beans Libraries
WebRoot
META-INF
WEB-INF
lib
web.xml
WebServices
services.xml
打开web.xml文件,可以看到如下片断:
<servlet>
<servlet-name>XFireServlet</servlet-name>
<servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
2、编写提供服务的业务类
在com.server.service(Package)里,新建两个java类,一个是IFileUploadUtil,另一个是FileUploadUtil。其中IFileUploadUtil是interface,内有一个fileUpload的抽象方法,而FileUploadUtil则是IFileUploadUtil接口的实现类。代码如下
package com.server.service;
public interface IFileUploadUtil {
/**
* 文件上传
* @param fileByteBuf 要上传的文件的字节流
* @param strRoot 上传目的地路径
* @param fileName 自定义文件名
* @return 上传成功则返回"ok",否则则返回"err:****"错误信息
*/
public abstract String fileUpload(byte[] fileByteBuf,String strRoot,String fileName);
}
package com.server.service;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileUploadUtil implements IFileUploadUtil {
public String fileUpload(byte[] fileByteBuf, String strRoot, String fileName) {
// 验证文件字节数组是否为空
if (fileByteBuf == null || fileByteBuf.length == 0)
return "err:上传文件的字节数组为空!";
//验证上传目的地路径是否存在
if (strRoot == null || strRoot == "")
return "err:上传目的地路径为空!";
//验证指定的文件名是否为空
if (fileName == null || fileName== "")
return "err:指定的文件名为空!";
if (fileName.lastIndexOf(".") == -1)
return "err:指定的文件名无后缀名!";
/**
* 声明四种I/O流
*/
ByteArrayInputStream fInStream = null;// 文件输入流
BufferedInputStream bInStream = null;// 输入缓冲流
OutputStream fOutStream = null;// 输出流
BufferedOutputStream bOutStream = null;// 输出缓冲流
try {
/**
* 赋值
*/
//得到字节数组输入流
fInStream = new ByteArrayInputStream(fileByteBuf);
//得到输入缓冲流
bInStream = new BufferedInputStream(fInStream);
//判断上传的目的地路径是否是目录,不是则新建目录
File folderSave = new File(strRoot);
if (!folderSave.isDirectory())
folderSave.mkdirs();
//验证目标文件
File fileSave = new File(strRoot + "/" + fileName);
if (fileSave.exists()){//当此抽象路径名表示的文件存在时
if (!fileSave.canWrite())
return "err:文件不可写入!";
}else if (!fileSave.createNewFile())
return "err:文件不能新建!";
//得到输出流
fOutStream = new FileOutputStream(fileSave);
//得到输出缓冲流
bOutStream = new BufferedOutputStream(fOutStream);
/**
* 循环
*/
int intByte = 512 * 1024;//缓冲区大小
byte[] fileData = new byte[intByte];//定义一个缓冲区
int intIndex = 0;
while ((intIndex = bInStream.read(fileData, 0, intByte)) != -1) {
bOutStream.write(fileData, 0, intIndex);
bOutStream.flush();
}
folderSave = null;
fileSave = null;
} catch (IOException e) {
return ("err:" + e.getMessage());
} finally{
/**
* 用完后,关闭I/O流
*/
try {
if (fInStream != null) {
fInStream.close();//关闭方法无效?!!!
fInStream = null;
}
if (bInStream != null) {
bInStream.close();
bInStream = null;
}
if (fOutStream != null) {
fOutStream.close();
fOutStream = null;
}
if (bOutStream != null) {
bOutStream.close();
bOutStream = null;
}
} catch (IOException e) {
return ("err:" + e.getMessage());
}
}
return "ok";
}
}
3、配置services.xml
我的代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xfire.codehaus.org/config/1.0">
<service>
<name>FileUpload</name>
<namespace>server</namespace>
<serviceClass>com.server.service.IFileUploadUtil</serviceClass>
<implementationClass>com.server.service.FileUploadUtil</implementationClass>
<style>wrapped</style>
<use>literal</use>
<scope>application</scope>
</service>
</beans>
Web Services的定义包含在元素中,它还含有一些子元素。
第一个子元素(name)是FileUpload,它可以是你提供任何的合法名字。这将会被客户端程序和其它需要定位你的服务的组件用到。例如,在服务准备好以后,你将在浏览器上使用这个名字来查看WSDL。
下一个子元素(namespace)是任何合法的XML名字都是可以的。用来唯一标识你的服务的各个参数。(注释@)
注释@:Namespace派什么用?namespace的作用是要避免命名冲突。如果我建立一项Web
Service,其中的WSDL文件包含一个名为"foo"的元素,而你想要使用我的服务与另一项服务连接作为补充,这样的话另一项服务的WSDL文件就不能包含名为"foo"的元素。两个服务器程序只有在它们在两个事例中表示完全相同的东西时,才可以取相同的名字。如果有了表示区别的namespace,我的网络服务里的"foo"就可以表示完全不同于另一个网络服务里"foo"的含义。在你的客户端里,你只要加以限制就可以引用我的"foo"。
serviceClass元素包含了Java类的名字,它指定了方法签名。在我们的例子中,它是接口IFileUploadUtil。如果Java类没有实现任何接口,你就需要把类的名字放在这里。在你的Java类或者接口中可能有几个方法。只需要一个入口把它们全部发布为Web Services。
implementationClass保存了实现方法的Java类名。这是一个可选元素。如果上一个元素包含了一个接口,那么相应的实现类必须在这里指定。
4、测试服务是否正常
发布项目Web_Server到Tomcat5.5中,启动Tomcat5.5,查看地址是:http://127.0.0.1:8080/Web_Server/services/FileUpload?wsdl,可看到如下信息:
<?xml version="1.0" encoding="UTF-8" ?>
- <wsdl:definitions targetNamespace="server" xmlns:tns="server" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="server">
- <xsd:element name="fileUpload">
<xsd:element maxOccurs="1" minOccurs="1" name="in0" nillable="true" type="xsd:base64Binary" />
<xsd:element maxOccurs="1" minOccurs="1" name="in1" nillable="true" type="xsd:string" />
<xsd:element maxOccurs="1" minOccurs="1" name="in2" nillable="true" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
- <xsd:element name="fileUploadResponse">
<xsd:element maxOccurs="1" minOccurs="1" name="out" nillable="true" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
- <wsdl:message name="fileUploadResponse">
<wsdl:part name="parameters" element="tns:fileUploadResponse" />
</wsdl:message>
- <wsdl:message name="fileUploadRequest">
<wsdl:part name="parameters" element="tns:fileUpload" />
</wsdl:message>
- <wsdl:portType name="FileUploadPortType">
- <wsdl:operation name="fileUpload">
<wsdl:input name="fileUploadRequest" message="tns:fileUploadRequest" />
<wsdl:output name="fileUploadResponse" message="tns:fileUploadResponse" />
</wsdl:operation>
</wsdl:portType>
- <wsdl:binding name="FileUploadHttpBinding" type="tns:FileUploadPortType">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
- <wsdl:operation name="fileUpload">
<wsdlsoap:operation soapAction="" />
- <wsdl:input name="fileUploadRequest">
<wsdlsoap:body use="literal" />
</wsdl:input>
- <wsdl:output name="fileUploadResponse">
<wsdlsoap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="FileUpload">
- <wsdl:port name="FileUploadHttpPort" binding="tns:FileUploadHttpBinding">
<wsdlsoap:address location="http://127.0.0.1:8080/Web_Server/services/FileUpload" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
这个XML文档叫做服务的WSDL。如果你看到了,这就是你的应用作为Web Service已经可用的第一个证明。
但是这个测试是不够的。可能会发生这种情况,可以看到WSDL,但是从客户端程序可能会访问不到服务。因此为了核实服务是否可以访问了,我们必须使用一个客户端进行服务的实际调用来进行一个真正的测试
三、编写客户端
到此为止,服务端已经编好了,我们现在来编写一个Web Project来作客户端。
1、创建Web Project
打开MyEclipse中File----->New---->Project,选择(Java)Web Project,点击Next,Project Name为Web_Client,建名为com.client.service的Package。
2、自动生成web serives客户端
选择菜单File----->New----->Other ,选择XFire文件夹下的Code generation from WSDL document,点击“Next”,显示“WSDL 2 Java Code generator with XFire”界面,
在WSDL URL or path处填写“http://127.0.0.1:8080/Web_Server/services/FileUpload?wsdl”(注意此时,服务端项目确保还在Tomcate5.5中跑),
Output directory处选择“/Web_Client/src”,
Package处则选择com.client.service,
点击“Finish”即可。
3、添加XFire类库
此时,在调用服务之前,还有一个重要的步骤,从Web_Client项目的右键菜单里调出Properties配置窗口,选中左面一栏中的XFire项,右面会列出所有与XFire运行有关的类库。我们在原有类库基础上再勾选第一个类库(Commons Codec)和第六个类库(Commons HttpClient),点“OK”完成操作。
4、编写调用上传服务的JSP文件
由于我们使用commons-fileupload(-1.1)组件来进行操作,所以需要向项目Web_Client中导入commons-fileupload-1.1.jar和commons-io-1.1.jar。
上传JSP名称为index.jsp,代码如下:
<%@page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
<%@page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%>
<%@page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%>
<%@page import="org.apache.commons.fileupload.FileUploadException"%>
<%@page import="org.apache.commons.fileupload.FileItemFactory"%>
<%@page import="org.apache.commons.fileupload.FileItem"%>
<%@page import="java.util.List"%>
<%@page import="com.client.service.FileUploadClient"%>
<%@page import="com.client.service.FileUploadPortType"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>上传文件</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<%
try {
//得到上传文件转化的字节数组
FileItemFactory factory = new DiskFileItemFactory();
System.out.println("-----1------");
ServletFileUpload upload = new ServletFileUpload(factory);
System.out.println("-----2------");
List fileItems = upload.parseRequest(request);
System.out.println("-----3------");
FileItem item = (FileItem)fileItems.get(0);
System.out.println("-----4------");
byte[] fileBytes = item.get();
System.out.println("上传的文件名:" + item.getName());
System.out.println("原始文件名称:" + item.getName().substring(item.getName().lastIndexOf("\\") + 1));
System.out.println("文件MINI类型:" + item.getContentType());
System.out.println("文件大小:" + item.getSize());
System.out.println("字节长度:=" + fileBytes.length);
System.out.println("item.getFieldName:" + item.getFieldName());
//调用web service的上传方法
FileUploadClient client = new FileUploadClient();
System.out.println("-----2--1------");
FileUploadPortType port = client.getFileUploadHttpPort();
System.out.println("-----2--2------");
//参数:文件的字节数组,上传目的地路径,文件名称
String returnValue = port.fileUpload(fileBytes,"E:\\temp",item.getName().substring(item.getName().lastIndexOf("\\") + 1));
System.out.println("-----2--3------");
//打印返回值
System.out.println("returnValue = " + returnValue);
}catch (FileUploadException e){
e.printStackTrace();
//打印该块代码中的异常
System.out.println(e.getMessage());
}
%>
<form name="upload" action="" method="post" enctype="multipart/form-data">
<table align="center">
<tr><td align="center">上传文件</td></tr>
<tr><td><input type="file" name="file"></td></tr>
<tr><td><input type="submit" name="go" value="提交"></td></tr>
</table>
</form>
</body>
</html>
5、运行测试客户端
发布项目Web_Client到Tomcate5.5中,启动Tomcate5.5后,注意:客户端和服务端项目都要跑起来。
打开http://127.0.0.1:8080/Web_Client/ ,进入上传页面,选择一个文件上传,如我上传的是xfire-distribution-1.2.6-sources.jar。上传成功后,在控制台上打印如下信息:
-----1------
-----2------
-----3------
-----4------
上传的文件名:c:\documents and settings\zy20022630\桌面\xfire-distribution-1.2.6-sources.jar
原始文件名称:xfire-distribution-1.2.6-sources.jar
文件MINI类型:application/x-zip-compressed
文件大小:544149
字节长度:=544149
item.getFieldName:file
-----2--1------
-----2--2------
-----2--3------
returnValue = ok
上述信息表示上传成功,在服务端项目所在的主机里相应位置(E:\\temp)可看到上传的文件。
到此已全部完成XFire生成和调用web service服务的操作!!!