开发 web 服务,第 3 部分 : 使用 Apache CFX 构建 File uploading web 服务

本教程演示了如何开发 CXF Web 服务,该服务可以从用户处上传一个提交的文件并保存到特定目录。该示例使用应用广泛的 Eclipse IDE 构建。

Kuntal Ganguly, 初级开发人员, IBM China

目前在加尔各答 Protech Infosystems Pvt. Ltd 公司担任初级开发人员。Kuntal 曾经接触过广泛的开源和商业工具(WASCE、Eclipse、Mule ESB、EZlegacy、Active MQ、Birt 和 DB2 express C)以及各种技术(GWT 和 Android)



Partha Goswami, 初级开发人员, IBM China

作者照片目前在加尔各答 Protech Infosystems Pvt. Ltd 公司担任初级开发人员。他曾经接触过广泛的开源和商业工具(WAS CE、Eclipse、Mule ESB、EZlegacy、Active MQ、Birt 和 DB2 express C)和技术(GWT 和 RSS)。



2011 年 10 月 17 日

引言

带有 SOAP 消息的二进制数据是通过 Base64 格式发送的,因为 SAOP 消息基于普通文本,因此当二进制数据被转换为 Base64 格式时,其大小会增加。并且,对于大型附件,这有可能会中断应用程序并因为内存问题而使服务器停止运行。MTOM (SOAP Message Transmission Optimization Mechanism) 采用 base64Binary 格式对二进制数据编码,并以二进制附件的方式发送数据,而不是将其保存为 SOAP 消息,因此提供了一种简洁的机制传递二进制数据,如 PDF、Doc、图像和其他文档类型。MTOM 使用 XML-binary Optimized Packaging (XOP) 包传输二进制数据。CXF 通过 XOP 实现提供 MTOM 支持。

本教程是共三部分的系列文章的最后一篇,将描述如何使用 Apache CXF 开发一个 File uploading Web 服务。

关于本系列

本系列教程讲述 Web 服务的基本概念,以及使用不同的 SOAP 引擎(如 Apache AXIS2、 Apache CXF 和 JAX-WS)开发 Web 服务的不同方法。本系列教程还提供了一个通过使用 MTOM (SOAP Message Transmission Optimization Mechanism) 发送带 SOAP 消息的大型附件的解决方案,MTOM 对 base64Binary 格式的二进制数据进行编码,并将数据作为二进制附件发送,而不是将它作为真正的 SOAP 消息。本系列还会演示如何通过使用 SAAJ API 进行简单的方法调用来读取和编写基于 SOAP 的 XML 消息,而且您可以选择通过 Internet 发送和接收此类消息。

第 1 部分 从简单的内容开始,先解释了 Web 服务背后的基本概念,并展示了如何使用 Axis2 运用不同的方法(代码优先和契约优先)来开发 Web 服务。

第 2 部分 首先使用 JAX-WS 简单地开发了一个 Hello User Web 服务,然后进一步展示了一个使用 JAX-WS 和 MOTO 的 File Download Web 服务(客户端可以通过 Web 服务下载文件并存储在其所在的位置)示例。该部分还展示了如何从 SAAJ 客户端调用 Web 服务。

第 3 部分 简单地展示了如何通过 XOP 实现、使用 Apache CXF 对 MTOM 的支持开发 File uploading Web 服务(客户端可以上传文件/附件到 Web 服务)。

关于本教程

本教程演示了如何开发可以从客户机将一个文件上传到服务器的 Web 服务。客户端应用程序提交一个文件位置并调用该 Web 服务,后者逐字节接收文件并将其存储到一个固定的指定位置。

目标

在本教程中,您将学会如何:

  • 使用 CXF 构建一个 Web 服务,并将其部署在 Tomcat 服务器。
  • 了解如何使用 MTOM 标准发送大型二进制附件。

先决条件

本教程假设您熟悉 Eclipse IDE 的一些基本概念,包括视图、编辑器、面板等等,以及 Java™ 和 Web 服务的一些基本编程概念。有关 Eclipse、Java 和 Web Services 的简介,请参见参考资料。

需要使用的软件

  • CXF-bin
  • Tomcat
  • Eclipse(可选)

简介

什么是 Web 服务?

Web 服务是对应用程序功能的网络访问接口,它是使用标准 Internet 技术构建的。

Web 服务背后的基本概念是 SOA(面向服务架构),其中,应用程序不再是一个大的整体程序,而是被分为许多更小的、松散耦合的程序,并且所提供的服务与标准的、定义良好的接口松散耦合在一起。这些松散耦合的程序使架构变得极具扩展性,因为现在只需很小的代价就可以添加或移除服务。因此,通过组合和重用现有服务就可以创建新的服务。

由于基于标准的接口提供抽象机制,因此应用程序服务是否用 Java 编写以及浏览器是否用 C++ 编写,或者应用程序部署在 Unix 系统而浏览器部署在 Windows 系统上,这些都没有关系。Web 服务具有与平台无关的跨平台互操作性。互操作性是实现 Web 服务的主要获益。参见图 A 所示的基本 Web 服务架构。

图 1. Web 服务架构
The Web 服务架构

在 Web 服务架构中,服务提供商发布一个服务描述(通过服务注册库提供)。服务的使用者搜索服务注册库以查找符合要求的服务。服务使用者可以是人或程序。

服务提供商以服务的形式提供业务流程。服务的使用者将调用来自提供商的服务,实现某些业务目标。提供和使用服务的过程是通过使用服务提供商与使用者之间的目录服务实现的,采用代理的方式。将要提供给使用者的服务发布到代理中的目录服务。希望实现某些业务目标的使用者会发现来自代理的服务。如果找到了服务,将绑定该服务并执行处理逻辑。

什么是 CXF?

Apache CXF 是一种开源框架,为方便地构建和开发 Web 服务提供了健壮的基础架构。它让您创建高性能的、可扩展的服务,可以部署到基于 Tomcat 和 Spring 的轻量级容器中,以及更加高级的服务器基础架构中,如 JBoss、IBM® WebSphere® 或 Oracle WebLogic。

CXF 提供了许多服务构建选项。CXF 支持以下三种主要的服务类型:

  • SOAP - 该页面总结了创建 SOAP 服务的选项。
  • REST-ful - REST 支持
  • CORBA

配置和部署

该示例将展示如何配置和开发一个运行在服务器上的基于 CXF 的 Web 服务,该服务会上传客户端提交的文件。参见下列规范。

Tomcat Web 服务器 5.5 或更高版本:Tomcat servlet 引擎是一个开源包,是 Apache Software Foundation 的 Jakarta 项目的一部分。它是 servlet 和 JSP 规范的官方参考实现。Tomcat 可以作为一个独立的 Web 服务器使用,也可以作为一个 servlet/JSP 引擎实现。可以从 http://tomcat.apache.org/download-60.cgi 下载 Tomcat 的最新发行版。

Apache-cxf-2.3. 或更高版本: Apache CXF 是一个开源服务框架。CXF 帮助您使用前端编程 API(如 JAX-WS 和 JAX-RS)构建和开发服务。这些服务可以支持各种协议,如 SOAP、XML/HTTP、RESTful HTTP 或 CORBA,并可以使用多种传输方式,如 HTTP、JMS 或 JBI。您可以从 http://cxf.apache.org/download.html 下载最新版本。

Eclipse IDE:一种集成开发环境 (IDE),集编写、编辑、编译和运行计算机程序的所有工具于一体。并且,Eclipse 提供了出色的集成开发环境。您可以在 www.eclipse.org 找到 eclipse 的最新发行版。

设置环境

  1. 在系统中安装 Jdk 1.5 或更高版本。
  2. 下载了 apache-cxf 发行版后,设置 CXF_HOME 环境变量。
  3. 下载 Tomcat 的最新发行版,并设置 TOMCAT_HOME 环境变量。

创建 Web 服务

  1. JavaEE 透视图中 启动 Eclipse,并选择 File > New > Other > Dynamic Web Project,创建名为 ‘CxfService’ 的项目。
  2. 展开 CxfService Project 选项卡,选择 Java Resource: src 并创建 ‘com.ibm.uploadbean’ 包。
  3. com.ibm.uploadbean’ 包将包含一个简单的 java bean 类,该类将获取并设置文件名、文件类型和 DataHandler 类型。该 bean 将作为参数传递来调用该服务。因此,在该包下创建一个类,并命名为 ‘FileUploader’。该类的代码在清单 1 和图 2 中给出。
图 2. File Uploader bean 类
File Uploader bean 类
清单 1. FileUploader.java
package com.ibm.uploadbean;

       import javax.activation.DataHandler;

public class FileUploader
{
  private String Name;
  private String FileType;
  private DataHandler Dfile;

  public String getName()
  {
    return this.Name;
  }

  public void setName(String Name)
  {
    this.Name = Name;
  }

  public DataHandler getDfile()
  {
    return this.Dfile;
  }

  public void setDfile(DataHandler Dfile)
  {
    this.Dfile = Dfile;
  }

public String getFileType() {
    return FileType;
}

public void setFileType(String FileType) {
    this.FileType = FileType;
}
}
  1. 每个 Web 服务都需要一个 Service Endpoint Interface (SEI),通过该接口客户端可以调用实现类。现在选择 Java Resource: src,创建另一个名为 ‘com.ibm.uploadservice’ 的包。
  2. 创建一个名为 ‘UploadSEI’ 的接口,其中包含 ‘uploadFile’ 方法,如清单 2 和图 3 所示。
图 3. UploadSEI - Service Endpoint Interface
UploadSEI--Service Endpoint Interface
清单 2. UploadSEI.java
package com.ibm.uploadservice;

import javax.jws.WebParam;
import javax.jws.WebService;
import com.ibm.uploadbean.FileUploader;

	
	@WebService
	public interface UploadSEI {
	    
	    void uploadFile(@WebParam(name="Dfile") FileUploader Dfile);
	}
  1. 创建一个名为 ‘UploadServiceImpl’ 的服务实现类,它在 ‘com.ibm.uploadservice’ 包的内部实现接口。该类定义了实现方法 uploadFile,后者使用 FileUploader bean 作为其参数。参见下面的图 4 和清单 3。
图 4. 上传服务的实现
上传服务的实现
清单 3. UploadServiceImpl.java
package com.ibm.uploadservice;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.activation.DataHandler;
import javax.jws.WebService;

import com.ibm.uploadbean.FileUploader;

@WebService(endpointInterface = "com.ibm.uploadservice.UploadSEI",
		serviceName = "UploadService")


public class UploadServiceImpl implements UploadSEI{
	
	public void uploadFile(FileUploader Dfile) {

		DataHandler handler = Dfile.getDfile();
		try {
		    InputStream is = handler.getInputStream();

		    OutputStream os = new FileOutputStream(new File("E:/uploads/"
			    + Dfile.getName() +"."+ 
			    Dfile.getFileType()));
		    byte[] b = new byte[100000];
		    int bytesRead = 0;
		    while ((bytesRead = is.read(b)) != -1) {
			os.write(b, 0, bytesRead);
		    }
		    os.flush();
		    os.close();
		    is.close();

		} catch (IOException e) {
		    e.printStackTrace();
		}

	    }
	  }
  1. OutputStream” 将把文件保存到提供的指定位置。
  2. 下一步是创建配置文件 ‘cxf.xml’,该文件会根据实现类 ‘UploadServiceImpl’ 创建 JAX-WS 端点。确保该文件位于 ‘src’ 根文件夹中,否则根据您的文件路径编辑 Web.xml。参见图 5 和清单 4。
图 5. CXF 配置文件
CXF 配置文件
清单 4. cxf.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:jaxws="http://cxf.apache.org/jaxws"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
 		http://www.springframework.org/schema/beans/spring-beans.xsd
 		http://cxf.apache.org/jaxws
 		http://cxf.apache.org/schemas/jaxws.xsd">

  <import resource="classpath:META-INF/cxf/cxf.xml" />
  <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
  <jaxws:endpoint id="uploadfile"
                  implementor="com.ibm.uploadservice.UploadServiceImpl"
                  address="/UploadWS">
                  <jaxws:properties>
      <entry key="mtom-enabled" value="true"/>
    </jaxws:properties>	
    </jaxws:endpoint>
</beans>
  1. 编辑 Web-INF 文件夹中的 ‘Web.xml’ 文件。参见清单 5。
清单 5. Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<Web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:Web="http://java.sun.com/xml/ns/javaee/Web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/Web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>CxfService</display-name>
   <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:cxf.xml</param-value>
  </context-param>
  <listener>
    <listener-class>
      org.springframework.Web.context.ContextLoaderListener
    </listener-class>
  </listener>
  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>
        org.apache.cxf.transport.servlet.CXFServlet
    </servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>  
</Web-app>
  1. WebContent > Web-INF 下创建名为 ‘lib’ 的文件夹(参见图 5),然后在 lib 文件夹中包括以下 .jar 文件。您可以在已下载的 CXF 分配库中找到所有这些 jar 文件。

aopalliance-1.0.jar
asm-2.2.3.jar
commons-lang-2.4.jar
commons-logging-1.1.jar
cxf-api-2.1.5.jar
cxf-common-schemas-2.1.5.jar
cxf-common-utilities-2.1.5.jar
cxf-rt-bindings-soap-2.1.5.jar
cxf-rt-bindings-xml-2.1.5.jar
cxf-rt-core-2.1.5.jar
cxf-rt-databinding-jaxb-2.1.5.jar
cxf-rt-frontend-jaxws-2.1.5.jar
cxf-rt-frontend-simple-2.1.5.jar
cxf-rt-transports-http-2.1.5.jar
cxf-rt-ws-addr-2.1.5.jar
cxf-tools-common-2.1.5.jar
FastInfoset-1.2.2.jar
geronimo-activation_1.1_spec-1.0.2.jar
geronimo-annotation_1.0_spec-1.1.1.jar
geronimo-javamail_1.4_spec-1.3.jar
geronimo-jaxws_2.1_spec-1.0.jar
geronimo-stax-api_1.0_spec-1.0.1.jar
geronimo-ws-metadata_2.0_spec-1.1.2.jar
jaxb-api-2.1.jar
jaxb-impl-2.1.9.jar
neethi-2.0.4.jar
saaj-api-1.3.jar
saaj-impl-1.3.2.jar
spring-beans-2.0.8.jar
spring-context-2.0.8.jar
spring-core-2.0.8.jar
spring-Web-2.0.8.jar
wsdl4j-1.6.2.jar
wstx-asl-3.2.6.jar
xml-resolver-1.2.jar
XmlSchema-1.4.5.jar

错误将消失。查看下面的图 6。

图 6. CXF 配置文件
CXF 配置文件
  1. 右键单击项目,选择 Export > WAR file(参见图 7)。复制 WAR 文件并粘贴到 Tomcat_Home 下的 Webapps 目录。启动 Tomcat 服务器。
图 7. WAR 创建
WAR 创建
  1. 启动 tomcat 服务器后,Web 服务将被部署到服务器上。进入 Tomcat Manager,输入用户名和密码,然后登录。您会发现已部署的名为 ‘CxfService’ 的服务,单击该服务,将看到可用的服务及其 WSDL 位置。单击 location 超链接,查看 WSDL。参见图 8。
图 8. Tomcat 控制台
Tomcat 控制台

Service Endpoint - http://localhost:8080/CxfService/UploadWS
WSDL 位置 - http://localhost:8080/CxfService/UploadWS?wsdl

生成 Stub

要调用服务,客户端必须知道 Service Endpoint Interface 和 bean 文件,后者将作为参数进行调用。要获得这些内容,客户端可以通过服务的 WSDL 创建 stub。

CXF 发行版提供了一个名为 ‘wsdl2java.bat’ 的工具,该工具可以为特定服务创建 stub,同时为 WSDL 位置提供一些额外的参数。

从命令提示符中访问 $(CXF_HOME) 的 bin 目录,并输入以下命令。

wsdl2java –client –verbose http://localhost:8080/CxfService/UploadWS?wsdl

这将运行 bin 目录中的 wsdl2java.bat 文件。‘-client’ 选项为客户端主线生成开始(starting point)代码。‘–verbose’ 选项在生成代码的过程中显示注释。参见图 9。

在成功执行命令后,将发现在 $(CXF_HOME)/bin 目录的 ‘com.ibm.uploadservice’ 包下创建了 stub。

图 9. Stub 生成命令
Stub 生成命令

创建客户端

接下来,我们将创建客户端项目,以便可以使用 Web 服务。在本例中,客户端是一个 POJO 客户端,您还可以创建一个需要 Web 容器的客户端。执行以下步骤,开发一个客户端。

  1. 在 Eclipse 中,选择 File > New > Other > Dynamic Web project,创建一个名为 ‘CxfClient’ 的新项目。
  2. 创建一个名为 ‘com.ibm.uploadservice’ 的包(如在 stub 中),并将所有生成的 stub 复制并粘贴到其中。
  3. 创建另一个名为 ‘com.ibm.client’ 的包。在该包中创建一个名为 ‘Client’ 的新类。该类将通过生成的 stub 调用已开发的服务。该类将包含 main() 方法,因此执行将从这里开始。参见清单 6 中该类的代码。
图 10. 调用服务 java 类的客户端
调用服务 java 类的客户端
清单 6. Client.java
package com.ibm.client;
import java.io.File;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import com.ibm.uploadservice.*;


public final class Client {

  

    public static void main(String args[]) throws Exception {

    	JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

    	factory.getInInterceptors().add(new LoggingInInterceptor());
    	factory.getOutInterceptors().add(new LoggingOutInterceptor());
    	factory.setServiceClass(UploadSEI.class);
    	factory.setAddress
    	("http://localhost:8080/CxfService/UploadWS");
    	UploadSEI client =(UploadSEI) factory.create();

    	FileUploader file=new FileUploader();
    	    	
    	file.setName("Partha");
    	file.setFileType("doc");
    	
    	DataSource source = new FileDataSource(new File("D:/my_upload_doc.doc"));
    	file.setDfile(new DataHandler(source));
    	client.uploadFile(file);
    	System.exit(0);

       }
    }
  1. 不要忘记在 WebContent > Web-INF > lib 中包含前面提到的 .jar 文件。
  2. ‘DataSource’ 对象源代码将包含上传文件的理想位置。在本例中为 ‘D:/my_upload_doc.doc’,可根据您的文件进行相应修改。
  3. setName("Partha") 是所上传文件的保存名。修改 setFileType("doc") 参数可相应地设置文件类型。
  4. 您可能会在 ‘file.setDfile’ 中得到一个类型匹配错误,这可能是因为生成的 ‘FileUploade.java’ 有一个 ‘byte[]’ 变量,而不是 ‘DataHandler’ 变量。将 byte[] 修改为 DataHander 就可以解决该问题。您还应当在其中导入 ‘javax.activation.DataHandler’。在任何情况下,引用 清单 1 中创建服务时使用的 bean 类。
  5. 要运行客户端,右键单击 Client.java 文件并选择 Run as > Java Application。如果没有发生错误的话,您会发现您的文件以给定的名称保存在服务指定的位置中。

结束语和参考资料

在当今世界,系统之间的互操作性非常重要,Web 服务是面向服务架构的基础。这些 Web 服务引擎为应用程序开发人员提供了功能强大的工具集,可以集成企业业务应用程序并构建最新的、跨多个企业的应用程序。


下载

描述名字大小
本教程的样例代码code.zip10KB

参考资料

学习

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=765746
ArticleTitle=开发 web 服务,第 3 部分 : 使用 Apache CFX 构建 File uploading web 服务
publish-date=10172011