内容


健壮、可维护的客户端解决方案

Comments

引言

为什么使用 J2SE 客户端访问 Web 服务?

Jave 2 Standard Edition(J2SE)提供了一大套工具来构建丰富的图形用户界面(GUI)。遗憾的是,从历史上讲,客户端-服务器模型的 J2SE 程序带来了许多包袱:

  • 它们难以部署。
  • 通过它们的 Java 数据库连接(Java Database Connectivity,JDBC)驱动程序连接,它们使用了大量数据库服务器资源。
  • 它们依赖于数据库服务器安全性模型或需要基于客户端的机器的应用程序密码来应用特定于应用程序的安全性。

Java Web Start 和 Web 服务完全支持新的应用程序体系结构,这种体系结构带有所谓客户端的丰富 GUI。Java Web Start 负责 Web 上的所有安装、部署和更新问题。Web 服务技术通过集合 Web 服务中成百上千的用户的数据库连接来负责数据库服务器资源。安全性模型更简单了,因为 Web 服务逻辑现在能够使用运行在服务器环境中的 Java 程序可用的任何资源。

如果您想要学习如何将 J2SE 客户端连接到运行在 IBM WebSphere Studio 平台上的 Web 服务或想学习如何使用 Java Web Start 从 WebSphere Studio 部署 J2SE 客户端,您就应该学习本教程。

驱动需求

和所有的实用教程一样,这篇教程也是从现实世界对开发客户端的需求开始的。应用程序的要点在于精细地显示机器和雇员的工作时间安排。应用程序替代了白板上的磁铁和印刷的卡片。其关键的技术需求是:

  1. 确保应用程序可以连续显示时间安排,即使服务器在几个小时的时间间隔内不可访问也是如此。
  2. 给任何经授权的用户提供集中式、无人看守的部署。
  3. 读取和更新 IBM iSeries Server 数据库中的数据。
  4. 只使用当前支持的服务器技术来延期使用正在变得过时的应用程序。
  5. 在 Websphere Studio Application Developer 的环境中开发应用程序以便简化将来的维护。

头两项需求表明应该使用具有 Java Web Start 技术的 Java 2 Standard Edition(J2SE)客户端。J2SE 客户端可以在服务器停机时把数据安全地存储在客户端的计算机中。Java Web Start 可以提供集中式的自动部署。第三项需求提出了两种可供选择的客户端-服务器体系结构——Java 数据库连接(Java Database Connectivity,JDBC)和 Web 服务。这两种体系结构都已经部署在该客户端环境中,并且通过使用 Web 服务获得了更大的成功。一个应用程序运行在使用 KSoap 的 Sharp Zaurus 个人数字助理(Personal Digital Assistant,PDA)以进行 XML 解析。另一个 Web 服务应用程序同时在客户端和服务器上使用 Apache Axis 来实现远程方法调用。客户端是 J2SE 客户端,它也是在独立模式下使用的。

对 iSeries Websphere Sudio 平台的研究表明,Apache Axis Web 服务实现在以后将不被支持,而新的 Web 服务开发应该使用 Web Service 5.0.2 WS-I 标准。第四项需求强制要求使用 5.0.2 WS-I 标准。在开发工具内进行的最初测试表明对平稳发展路线的重大承诺是在第一次测试部署之前作出的。遗憾的是,使用 IBM WSDK V5.1 工具开发的 J2SE 客户端将不作为 J2EE 容器之外的标准客户端运行。实现完全成熟的 J2EE 应用程序是不可能的,因为 J2EE 技术对于简单的白板应用程序太过复杂。此外,从服务器中配置客户端的 J2EE 标准还不符合第一项要求当客户端重新启动之后在不使用服务器的情况下显示数据的需求。

有使 Java Web 服务的不同实现与 iSeries Server 互操作的方法吗?有,Sun Java Web Services Developer Pack 包含 J2SE 客户端代码生成和运行时库的不同实现,它与 Websphere Application Server 互操作。本教程将指导您如何同时使用 IBM 和 Sun 工具来创建和部署 Web 服务和 J2SE 客户端,以便构建与 IBM Websphere Studio Application Developer 内的 IBM Websphere Application Server Test Environment 互操作的 Java Web Start 应用程序。

本教程的目标

本教程的目标是展示通过用 Java Web start(JWS)开发的 Java 2 Standard Edition(J2SE)来访问运行在 Application Server 上的 Web 服务的细节。我们将演示如何:

  • 使用 Application Developer 从 Java Bean 构建 Web 服务。
  • 将您的 Device Developer 环境更改为使用 JSDK 1.4.x,同时保留运行最初的 IBM J2SDK Version 1.3 的能力。
  • 使用 Sun 的 Java Web Services Developer Pack(JWSDP)从 IBM 的 Web 服务描述语言(Web services deployment language,WSDL)文件生成 J2SE 客户端构件。
  • 使用 Application Server 中的 JWS 准备和部署 J2SE 客户端。

先决条件

在开始学习本教程之前,您应该理解 Java 编程、Device Developer 开发环境和 Web 服务体系结构等概念。本教程是在 Windows XP 工作站上开发的并且假定在 Windows 环境中开发和部署。在其他的平台上,您的步骤可能会有所不同。您的开发工作站应该安装以下组件:

  • 您可以从 java.sun.com 下载 Sun 的 Java 1.4.2 或更高版本的 Java 2 Software Development Kit(J2SDK)。为了顺利地完成 Ant 构建任务,请确保将 J2SDK 安装到您的 C: 盘的根目录中。不要接受将其缺省安装在 Program Files 目录下。
  • 在客户端计算机上安装 Sun 的 Java Runtime Environment(JRE)以与 J2SDK 相匹配。应该在客户端计算机上的任何 Java 1.4 JRE 的安装目录中安装 Java Web Start 客户sta务器和客户端计算机可以是相同的机器。
  • 您可以从 IBM developerWorks 下载 IBM Web Services Development Kit Version 5.1(WSDK 5.1)。
  • 您可以从 java.sun.com 下载 Sun 的 Java Web Services Developer Pack Version 1.3(JWSDP 1.3)。

在学习本教程的过程中,您将创建一组简单的 Web 服务来测试互操作性。样本服务实现既实现简单的请求也实现复杂的请求,并且返回类型,以便演示 Web 服务技术的实际使用。为了简单起见,在本教程中,您将从简单的 Java Bean 而不是通过数据库访问来生成 Web 服务。

本教程的工作是在两个工作区中完成的,一个工作区使用 IBM 提供的 Java SDK 1.3.1,一个工作区使用 Sun 的 Java SDK 1.4.2。两个工作区都是必需的,因为每个厂商的 Web 服务工作都需要它所需的运行时环境。使用两个工作区意味着运行两个独立的 Device Developer 进程。

现在,您已经有了您需要的每样东西,请从下面选择您喜欢的起点:

  • 从 Bean 到 Web 服务
  • 更改 Device Developer Java SDK
  • 构建 J2SE WSI Client
  • 使用 Java Web Start 部署客户端

从 Beans 到 Web 服务

创建 Web 项目

在本教程中,定义 Web 服务的第一步就是使用一开始安装的 Device Developer 在空的目录中创建新的 Web 服务。

  1. 首先创建一个空的工作区目录,然后在该目录中启动 Device Developer。我使用的是 C:\JavaWork\WsiInterop。请注意本教程的目录结构没有空格,因为客户端项目的 Ant 构建脚本只是在没有空格的路径名中才是有效的。

  2. 定位到新的空工作区目录并单击 OK 按钮。
  3. 在 Device Developer 完成了它的启动进程之后,创建一个新的动态 Web 项目。选择 File --> New --> Project
  4. 在左边的窗格中高亮显示 Web,在右边的窗格中高亮显示 Dynamic Web Project。按 Next 继续向导中的步骤。
  5. 将项目命名为 WsiSvc 并按 Finish 来创建项目。不需要配置高级选项。
  6. 当系统询问是否切换到 Web Perspective,请选择 Yes

创建包

对于新的 Web 项目,您可以创建包来包含 Java 代码类。Java 代码类分成单独的消息包和服务逻辑包,这样做的主要原因在于,Web 服务向导将为每个类生成三个助手类以作为 Web 服务返回对象。这些单独的包保留了 com.solutionst.wsimsg 包中的大部分内容。请遵循下面的步骤以创建包:

  1. 展开 WsiSvc 项目以显示文件夹。
  2. 右键单击 JavaSource 文件夹,并且选择 New --> Package
  3. 命名包,然后单击 Finish。对于本教程,将包命名为 com.solutionst.wsisvc
  4. 重复前面的步骤创建另一个包以包含消息结构。对于本教程,将第二个包命名为 com.solutionst.wsimsg

消息 Bean 概述

您的 Web 服务和它的客户端之间的服务依赖于包含所需结构的消息 Bean。有两种数据 Bean 包含关于部件和部件的装配的信息。有两种数组包装器 Bean 将来自服务器的响应传送到客户端。数组包装器技术是传输多个部件和装配以及传送异常条件或消息的方法。对两个厂商的开发库的试验表明,客户端库并不是如实地反映抛出的异常并且不能解析对象的数组。包含状态代码、消息和对象数组的包装器方法可用于在不跨 Web 服务边界传送异常的情况下传送正常的数据和异常条件。

创建消息 Bean

请遵循下面的步骤创建消息 Bean:

  1. 右键单击 Messages 包并选择 New,然后从弹出菜单中选择 Class。将该类命名为 Part
  2. 赋予给类一些不重要的特性,入下面的代码段所示:
    public class Part {
    
      private int partId = -1;
      private String partName = null;
    
      // more listing omitted
  3. 使用 Device Developer 向导为这些特性生成 getter 和 setter 方法,方式是右键单击源代码区并选择 Source,然后从弹出窗口中选择 Generate Getter and Setter。按一下 Select All 按钮,然后按 OK。向导将生成 getter 和 setter 方法。保存 Part.java 文件。
  4. 重复前面的步骤来创建具有所列出的特性的 Assembly 类。请注意包含组成 AssemblyPart 对象的数组来演示嵌套数组而仍然跨平台进行互操作的能力。
    public class Assembly {
    
      private int assemblyId = -1;
      private String assemblyName = null;
      private Part[] parts = null;
    
      // more listing omitted

消息 Bean 包装器

数组包装器类可用作 Web 服务的消息返回结构。状态代码可用于指示所请求的操作是完全成功还是完成失败。消息文本可用于传送可显示的文本。请遵循下列步骤来创建数组包装器消息:

  1. 右键单击 messages 包并选择 New,然后从弹出菜单中选择 Class。将该类命名为 PartArray
  2. 除了 Part 对象的数组之外,还给该类提供状态代码和消息特性。
    public class PartArray {
      
      private int statusCode = -9999;
      private String msg = null;
    
      private Part[] parts = null;
    
      // more listing omitted
  3. AssemblyArray 创建相似的结构。
    public class AssemblyArray {
    
      private int statusCode = -9999;
      private String msg = null;
    
      Assembly assemblies[] = null;
    
      // more listing omitted
  4. 再次使用 Device Developer code 向导为两个数组包装器类生成 getter 和 setter 方法。

服务逻辑 Bean

服务逻辑 Bean 实现了 Web 服务的核心逻辑。这些服务的目的在于演示 Web 服务的强大,它们能够通过有线线路返回返回简单的数据和复杂的数据,而只需部分开发人员做很好的工作。InterSvc Bean 提供:

  • 一个简单的“Hello”方法(sayHello),可以基于字符串参数返回字符串
  • 单个部件查找方法(getOnePart),在给定整数键值的条件下可以找到单个部件
  • Part 搜索方法(findParts),可以从字符串搜索参数中找到 Part 的数组
  • Assembly 查找方法(getOneAssembly),可以根据整数键值找到单个 Assembly Bean 及其组件部件的数组
  • Assembly 搜索方法(findAssemblies),可以找到带有组件部件的 Assembly Bean 的数组

对于本教程,数据检索(data retrieval)功能都嵌入了 InterSvc 类,目的是减少对数据库连接的外部依赖性。InterSvc 类的源代码如下所示:

public class InterSvc {

  public String sayHello(String inputName) {
    String result = "Hello, " + inputName;
    return result;
  }

  public PartArray getOnePart(int partToGet) {
    PartArray result = new PartArray();

    if (partToGet > 100) {
      result = new PartArray();
      Part parts[] = new Part[1];
      Part aPart = new Part();
      parts[0] = aPart;
      parts[0].setPartId(partToGet);
      parts[0].setPartName("Part " + Integer.toString(partToGet));
      result.setParts(parts);
      result.setMsg("OK");
      result.setStatusCode(0);
    } else {
      // the array must be present in the return structure
      // or the client libraries will throw an exception
      result.setParts(new Part[1]);
      result.setMsg("Invalid part number");
      result.setStatusCode(-1);
    }

    return result;
  }

  public PartArray findParts(String partName) {
    PartArray result = new PartArray();
    Part[] parts = null;

    if (!partName.equals("badName")) {
      parts = new Part[5];
      for (int i = 0; i < 5; i++) {
        PartArray arry = getOnePart(i + 1000);
        Part part = arry.getParts()[0];
        part.setPartName(partName + ": " + part.getPartName());
        parts[i] = part;
        result.setMsg("OK");
        result.setStatusCode(0);
      }
      result.setParts(parts);
    } else {
      result.setParts(new Part[1]);
      result.setMsg("Invalid part name " + partName);
      result.setStatusCode(-1);
    }

    return result;
  }

  public AssemblyArray getOneAssembly(int assyToGet) {
    AssemblyArray result = new AssemblyArray();

    if (assyToGet > 100) {
      Assembly assemblies[] = new Assembly[1];
      Assembly anAssembly = new Assembly();
      assemblies[0] = anAssembly;
      assemblies[0].setAssemblyId(assyToGet);
      assemblies[0].setAssemblyName("Assembly " + Integer.toString(assyToGet));
      PartArray pa = findParts("getOneAssembly");
      assemblies[0].setParts(pa.getParts());
      result.setAssemblies(assemblies);
      result.setMsg("OK");
      result.setStatusCode(0);
    } else {
      Assembly assemblies[] = new Assembly[1];
      result.setAssemblies(assemblies);
      result.setMsg("Invalid assembly number " + Integer.toString(assyToGet));
      result.setStatusCode(-1);
    }

    return result;
  }

  public AssemblyArray findAssemblies(String assyName) {
    AssemblyArray result = null;
    Assembly[] assemblies = null;

    if (!assyName.equals("badName")) {
      assemblies = new Assembly[2];
      for (int i = 0; i < 2; i++) {
        AssemblyArray arry = getOneAssembly(i + 2000);
        assemblies[i] = arry.getAssemblies()[0];
      }
      result = new AssemblyArray();
      result.setAssemblies(assemblies);
      result.setMsg("OK");
      result.setStatusCode(0);
    } else {
      assemblies = new Assembly[1];
      result.setAssemblies(assemblies);
      result.setMsg("Invalid assembly name " + assyName);
      result.setStatusCode(-1);
    }

    return result;
  }

}

创建测试服务器

下一步就是创建一个测试服务器来托管 Web 服务并检验该服务器是否将启动。Device Developer 的 Web 服务向导需要在生成 Web 构建之前在可运行的服务器上配置包含 Web 服务的项目。创建测试服务器最简单的方法就是简单地在服务器上运行 Web 项目并允许项目向导自动创建和配置服务器。

请遵循下列步骤来创建测试服务器并运行项目:

  1. 右键单击 WsiSvc 项目并从弹出菜单中选择 Run on Server
  2. Server Selection 向导中,指定创建一个新的服务器并从 Server Type 列表中选择 Test Environment
  3. Finish 启动服务器并运行项目。当 Web 浏览器报告 HTTP 404 - File not found error 时,请不要感到吃惊。作为一个 Web 服务项目,您还没有把缺省的 index.html 文件放在 WebContent 目录中。
  4. 一旦服务器启动了,就让它运行,因为您将需要它生成 Web 服务。

生成 Web 服务

Web 服务是本教程的中心,并且最后您可以使用 Device Developer 向导来创建它。下面是将您构建好的 InterSvc Bean 作为 Web 服务部署需要遵循的步骤:

  1. 如果您还没有进行到这一步,请切换到 WSAD Web 透视图。
  2. 展开项目和 JavaSource 文件夹,直到您可以看到 InterSvc.java Bean 为止。
  3. 右键单击 InterSvc.java Bean 并从 Web Services 菜单中选择 Deploy as Web service
  4. Deploy as Web Service 对话框出现时按 Finish,因为所有的缺省值对于本教程都是合适的。

生成测试 JSP

既然 Web 服务已经创建好了,现在就是生成简单的测试环境来测试服务逻辑的时候了。

  1. 右键单击 InterSvc.java 源文件并从弹出菜单中选择 Web Services --> Generate Sample Application
  2. Proxy to Sample Application 对话框出现后按 Finish

Web 浏览器将打开,允许您测试服务逻辑 Bean。该 Bean 与测试 JSP 的实际通信不是使用任何 Web 服务协议进行的。注意,复杂对象的返回值是最简单的 toString() 值。继续前进,看一看您的新应用程序。

创建 TCP 监视器

当事情变得越来越复杂时,为了全面地调试客户端程序,使用监视器来检查客户端和服务器之间传送的 XML 消息是非常有帮助的。幸运的是,Device Developer 有内置的 TCP 监视器。请遵循下列步骤来创建监视器服务器:

  1. 选择 File --> New 打开 New 对话框。
  2. 在左边的窗格中高亮显示 Server,在右边的窗格中高亮显示 Server and Server Configuration。按 Next 按钮继续。
  3. 将该服务器命名为 Monitor
  4. 滚屏至 Server 树形列表并展开 Other 节点。
  5. 高亮显示 TCP/IP Monitoring Server 并按 Next
  6. 输入 9080 作为 Remote Port 或输入用在您的测试 Web 浏览器中的 http: 端口地址。(当测试 Web 服务时,服务器端口地址是您的浏览器地址字段中 localhost: 之后的数字。
  7. Finish 按钮创建监视器。

配置 TCP 监视器

请检查生成的监视器配置的端口值是否正确,如果您的开发工作站有许多开发产品的许多版本,您就更应该这样做。缺省的监视器配置是不可能与您的环境相匹配的。根据惯例,把监视器端口设置为比 Device Developer 测试环境服务器端口高一个数字的值;也就是说,如果服务器端口是 7000,那么监视器端口就是 7001。

请进行检查,如果必要的话,改正监视器配置:

  1. 切换到 server 透视图。
  2. 在 Device Developer 主窗钩的左下部分中,双击 Monitor server 来打开监视器配置。
  3. 确保 Local port9081Remote port9080
  4. 保存并关闭配置。
  5. 返回到 Web 透视图。

启动 TCP 监视器

要启动监视器:

  1. WSAD workspace 窗口的底部选择 Servers 选项卡。
  2. 右键单击 Monitor server 并从弹出菜单中选择 Start

通过监视器重新测试服务,方式是将 Web 浏览器的地址从 http://localhost:9080/WsiSvc/sample/InterSvc/TestClient.jsp 更改为 http://localhost:9081/WsiSvc/sample/InterSvc/TestClient.jsp。您可以双击 TCP/IP 监视器标题栏以展开监视器并检查消息。在开发实际的客户端应用程序时,监视器是非常有帮助的。

创建 UTF-8 过滤器

关于正确地设置 HTTP Servlet 头中的字符编码的正确方式,以 Sun 和 Microsoft 为一方,以 IBM 为另一方,双方并没有就此达成一致的意见。虽然采用什么样的字符编码方式在您最初开发 Web 服务的过程中并不明显,但是当您试图让每个人都很好地使用您的 Web 服务时,它就变成了一个突出的问题。Microsoft 和 Sun 的工具将字符编码设置为用引号括起来的字符值 "utf-8",而 Device Developer Server 平台将这个值解释为一个错误,并且只接受不带引号的 utf-8。幸运的是,当主要厂商组成的互操作性组织决定如何解决这个问题时,就会找到一种简单的解决方案。就目前来说,可以实现一个标准的 JSP 2.3 Servlet 过滤器来按照服务中的方式更改字符编码值,操作步骤如下:

  1. 创建一个新包,要这样做,您可以右键单击 JavaSource 文件夹并从弹出菜单中选择 New,然后选择 Package。本教程将该包命名为 com.solutionst.filter
  2. 首先使用类向导创建一个新的 Filter 类,要这样做,您可以右键单击新包并选择 New,然后选择 Filter
  3. 通过使用 Browse 按钮将 Java 包设置为新创建的包。将 Class 名设置为 Utf8Filter。按 Finish 以完成类的创建。不要试图为这个简单的过滤器实现更改 SuperClass。向导将创建大部分所需的 Java 代码并且打开一个新的窗口,允许您编辑 Utf8Filter 的源代码。
  4. 如下修改所生成的代码的 doFilter 方法:
      public void doFilter(
        ServletRequest req,
        ServletResponse resp,
        FilterChain chain)
        throws ServletException, IOException {
    
        // Set up some logging 
        String contentType = req.getContentType();
        String charEncoding = req.getCharacterEncoding();
        System.out.println(
          "Utf8Filter: contentType="
            + contentType
            + " charEncoding="
            + charEncoding);
        // Do the actual work
        req.setCharacterEncoding("utf-8");
        chain.doFilter(req, resp);
    
      }

    对于生产使用,请除去对 System.out 的日志记录。

部署 UTF-8 过滤器

下一步是通过编辑项目的 Web Deployment Descriptor 来在项目环境中部署过滤器:

  1. 双击项目中的 Web Deployment Descriptor 项以打开编辑器。
  2. 单击 Filters 选项卡以显示可显示的过滤器。
  3. 在编辑器左边的窗格中选择 Utf8Filter 并修改过滤器的 URL Mappings 以包括所有的 URL 路径(/*)。
  4. 修改部署描述符文件并退出编辑器。

J2SE 客户端

更改 Device Developer Java SDK

为了通过您的 J2SE 客户端运行 Sun JWSDP 库,您需要具有我们从 Device Developer 中启动的所有程序都可用的 1.4.x J2SDK 运行时环境。为了达到这个目的,您可以可以创建一个新的 Device Developer 启动快捷方式并修改安装文件。正是由于有了 Genady Beryozkin,我们才可以在 http://www.genady.net/forum/viewtopic.php?t=9 发布转换 SDK 的方向。

更改 Device Developer 所用的 J2SDK 有两个关键步骤——更改 Device Developer 启动快捷方式的目标并修改 wsappdev.ini 文件。要更改快捷方式的目标,请遵循下列步骤:

  1. 找到 Application Developer 启动图标并把它复制到桌面。(在 Windows XP 中,右键单击图标,选择 Copy,然后把它粘贴到桌面。)
  2. 将这个启动图标重命名为 WSAD 1.4.2,以区别于原始的图标。
  3. 右键单击图标并从弹出菜单中选择 Properties 以显示启动特性。
  4. 将目标行从 "C:\Program Files\IBM\WebSphere Studio\Application Developer\v5.1\wsappdev.exe" 更改为 "C:\Program Files\IBM\WebSphere Studio\Application Developer\v5.1\wsappdev.exe" -vm C:\j2sdk_nb\j2sdk1.4.2\bin\javaw.exe 。 确保引用您的 J2SDK 安装的正确位置。

在创建和修改了新的快捷方式之后,在 Device Developer Application 目录中编辑 wsappdev.ini 文件并注释掉 VMArgs 行。

#VMArgs=-Xj9

对于缺省的 Windows 安装,可以在 C:\Program Files\IBM\WebSphere Studio\Application Developer\v5.1 目录中找到 wsappdev.ini 文件。

使用 Java 1.4.2 的新客户端项目

既然您已经有了使用 Java 1.4.2 的 Device Developer 环境,您就可以开始创建客户端应用程序了。

  1. 首先创建一个空的工作区目录并从 WSAD 1.4.2 链接中启动 Device Developer。在本例中,客户端目录为 WsiInterOpClient
  2. 定位到新的工作区目录并对单击 OK 按钮。对于本教程,工作区目录为 WsiInterOp
  3. 检验您运行的是否是 J2SDK 1.4,检验的方式是从 Help 菜单中选择 About IBM Websphere Studio Application Developer

  4. 按一下 Configuration Details 按钮。检验下面的条目是否在 Device Developer 配置中:
         java.class.version=48.0
         java.endorsed.dirs=C:\j2sdk_nb\j2sdk1.4.2\jre\lib\endorsed
         java.ext.dirs=C:\j2sdk_nb\j2sdk1.4.2\jre\lib\ext
         java.home=C:\j2sdk_nb\j2sdk1.4.2\jre

创建简单的 J2SE 客户端

J2SE 客户端将构建在运行 Java 1.4.2 的单独 Device Developer 实例中,因为由 Sun Java Web Services Developer Pack(JWSDP)和 JWSDP 工具本身生成的客户端都需要 Java 1.4.2。

请遵循下列步骤创建包含 srcbin 目录的新 Java 项目:

  1. 切换到 Java 透视图并创建一个新的空 Java 项目,名为 WsiClient
  2. 右键单击新项目并从弹出菜单中选择 Properties
  3. 导航到 Java Build Path 窗格并选择 Source 选项卡。
  4. 按一下 Add Folder 按钮并创建一个新的名为 src 的文件夹,然后按 OK
  5. Source Folder Added 对话框中,当系统询问是否更新源路径和输入路径时,回答 Yes
  6. src 文件夹下创建一个新的包以包含新的客户端,要这样做,您可以右键单击 src 文件夹并选择 New,然后从弹出菜单中选择 Package。本教程将该包命名为 com.solutionst.wsiclient

所需的 Sun JWSDP JAR 文件

在创建了基本的项目之后,SUN JWSDP JARs 需要包括在项目之内。

  1. 创建新的名为 sunJars 的文件夹来包含 Sun JWSDP JAR 文件。要这样做,您可以右键单击项目并选择 New,然后从弹出菜单中选择 Folders
  2. 使用 Windows 浏览器或 File Import 菜单选择,从 JWSDP 环境导入 Sun JAR,直到它包含下列文件:
      activation.jar
      jax-qname.jar
      jaxp-api.jar
      jaxrpc-api.jar
      jaxrpc-impl.jar
      jaxrpc-spi.jar
      mail.jar
      saaj-api.jar
      saaj-impl.jar
  3. 修改项目的构建特性以包括这些构建文件,要这样做,您可以双击项目的名称并从弹出菜单中选择 Properties
  4. Properties 对话框中,在左边的窗格中高亮显示 Java Build Path,在右边的窗格中选择 Libraries 选项卡。
  5. 按一下 Add JARs 按钮以显示 JAR Selection 对话框。展开该文件夹,高亮显示 Sun JAR 文件并按 OK
  6. 按一下 OK 退出 Properties 对话框。

ANT 构建环境

Sun JWSDP Tutorial 使用 Ant 来构建它的所有样本,可以通过除去 Device Developer 环境中不需要的任务来修改这种机制以为本教程所用。

  1. 首先在 Java 项目的根中创建一个新的文件夹,要这样做,您可以是右键单击该项目的名称并选择 New,然后从弹出菜单中选择 Folder
  2. 输入 build 作为文件夹的名称,然后按一下 Finish 按钮。
  3. 在构建文件夹中创建一个新的名为 build.xml 的文件,要这样做,您可以右键单击构建文件夹并选择 New,然后从弹出菜单中选择 File
  4. 将该文件命名为 build.xml 并按一下 Finish 按钮。
  5. 重复前面的步骤以创建其他的三个文件,它们分别名为 build.propertiescommon.xmlconfig-wsdl.xml

Ant 是一个灵活的基于 Java 的工具,它以可靠且可重复的方式自动完成许多开发任务。与 Sun JWSDP 一起交付的 Ant 脚本使示例从代码生成一直到编译再到运行已完成的应用程序,所有这些都是自动完成的。在 Device Developer 环境中,您只需要使生产任务自动进行。

build.xml

build.xml 文件驱动整个构建过程。

<!DOCTYPE project [
  <!ENTITY jaxrpccommon SYSTEM "common.xml">
]>

<project name="static-client" default="build" basedir=".">

  <property file="build.properties"/>

  &jaxrpccommon;

  <target name="build" depends="generate-stubs"
     description="Executes the targets needed to build a static stub client.">
  </target>

</project>

build.xml 文件的细节解释如下:

  • 该文件首先引用名为 common.xml 的通用任务定义文件。
  • 项目被命名为 static-client 并且具有 build 的缺省目标,这意味着如果 Ant 在不执行操作的情况被调用,build 目标就将运行。basedir 引用是当前的文件夹。这个 basedir 路径扩展为 build.xml 目录的全操作系统路径。 path is expanded to the full operating system path of the build.xml directory. 这个全路径然后可用作 Ant 构建环境中任何相对路径的前缀。因为 Ant 的文件查找行为的路径扩展。所以客户端项目路径中的文件夹名不能包含空格。
  • build.properties 文件是保存可以经常改变的变量的地方。
  • 在构建中的此处,&jaxrpccommon 引用调用 common.xml 的内容。
  • 最后,定义构建目标,以便前面成功地执行生成存根目标(可以在 common.xml 中找到)。依赖(depends)选项会告诉 Ant 工具在调用当前的目标之前调用指定的目标。当您阅读 common.xml 文件时,您将注意到依赖机制用于模块化脚本目标。

common.xml

common.xml 文件描述了存根生成任务的细节。

<target name="prepare" description="Creates the build directory">
	<echo message="Creating the required directories...." />
	<mkdir dir="../src/${srcPackagePath}" />
</target>

<target name="set-wscompile">
	<condition property="wscompile" value="${wscompile.dir}/wscompile.bat">
		<os family="windows" />
	</condition>
	<condition property="wscompile" value="${wscompile.dir}/wscompile.sh">
		<not>
			<os family="windows" />
		</not>
	</condition>
</target>

<target name="run-wscompile" depends="prepare,set-wscompile" 
  description="Runs wscompile">
	<echo message="Running wscompile:" />
	<echo message="  ${wscompile} ${param1}" />
	<exec executable="${wscompile}">
		<arg line="${param1}" />
	</exec>
</target>

<target name="generate-stubs" 
  description="Runs wscompile to generate the client stub classes">
	<antcall target="run-wscompile">
		<param name="param1" 
		  value="-gen:client -f:documentliteral -d ../bin -s ../src -keep 
            -classpath ../sunJars ${config.wsdl.file}" />
	</antcall>
</target>

下面解释 common.xml 的细节:

  • prepare 目标创建了一个源目录来包含生成的代码(如果目录不存在的话)。${srcPackagePath} Ant 变量是在 build.properties 文件中设置的。
  • set-wscompile 目标设置了调用 JWSDP wscompile 的细节。Ant 变量还是设置在 build.properties 文件中。
  • run-wscompile 目标在本地操作系统中执行 wscompile 命令。
  • generate-stubs 目标设置 wscompile 命令所需的命令参数并且调用 run-wscompile 目标。param1 值时更改 wscompile 命令选项的地方。

build.properties

build.properties 文件告诉 Ant 工具在哪里查找构建所需的变量值。该文件是自描述的,而在找不到文件或目录的情况下最常导致 Ant 构建问题。

# URL for clients to access the Web service
endpoint.address=http://localhost:9081/WsiSvc/services/InterSvc
# Source package name for generated code
srcPackagePath=com/solutionst/wsiclient

# Installation directory of the Sun Java Web Services Developer Pack
jwsdp.home=c:/jwsdp-1.3
# JAX-RPC path within the JWSDP home directory
jaxrpc.home=${jwsdp.home}/jaxrpc
# Directory for the wscompile command
wscompile.dir=${jaxrpc.home}/bin

# The file driving the wscompile command
config.wsdl.file=config-wsdl.xml

# Sun jar files from the JWSDP environment
jax-qname.jar=../sunJars/jax-qname.jar
jaxp-api.jar=../sunJars/jaxp-api.jar
jaxrpc-api.jar=../sunJars/jaxrpc-api.jar
jaxrpc-impl.jar=../sunJars/jaxrpc-impl.jar
jaxrpc-spi.jar=../sunJars/jaxrpc-spi.jar
javamail.jar=../sunJars/mail.jar
saaj-api.jar=../sunJars/saaj-api.jar
saaj-impl.jar=../sunJars/saaj-impl.jar

config-wsdl.xml

config-wsdl.xml 文件用于定义 Web 服务描述语言(Web Services Definition Language)文件的位置和生成的 Java 代码的包名。

<?xml version="1.0" encoding="ISO-8859-1"?>
<configuration 
 	xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
  <wsdl location="http://localhost:9081/WsiSvc/wsdl/com/solutionst/wsisvc/InterSvc.wsdl"
       packageName="com.solutionst.wsiclient"/>
</configuration>

静态存根

静态存根是实现 Web 服务 Bean 的公共接口的存根类,这些公共接口定义在 Web 服务的 Web 服务描述语言(Web Services Definition Language)文件中。静态存根是开发人员要实现的最简单的 Web 服务客户端,因为客户端程序逻辑可认为是使用客户端计算机的本地简单对象。查找和激活 Web 服务调用以及解析结果等繁琐的细节都是由 Sun 和 IBM 提供的开发者工具管理的。这种方法的一个不利的方面是,当 Web 服务消息结构改变时需要重新生成客户端存根并重新部署客户端程序。

根据 Ant 构建环境生成静态存根:

  1. 在 Web 服务客户端工作区中展开项目树以显示 build.xml 文件。
  2. 右键单击 build.xml 文件并从弹出菜单中选择 Run Ant
  3. WsiClient build.xml 对话框中,确保只有 build 目标被选中并按一下 Run

    Ant 将调用全部所需的任务来创建类包和类存根。Ant 输出将显示在控制台窗口中以便您查看。在尝试编译和运行客户端之前请确保改正系统报告的任何错误。通常的错误包括没有服务器运行在您的其他 Device Developer 实例中、config-wsdl.xml 文件中的 WSDL 路径不正确以及 build.properties 路径设置中的其他错误。

  4. 在成功地生成了 Ant 存根之后,通过右键单击项目名并从弹出菜单中 refresh 来刷新该文件在 Device Developer 中的视图。这个刷新步骤是必要的,因为 Ant 构建生成了许多文件,而 Device Developer 环境并不知道这些。

J2SE 客户端

由于生成的存根非常的强大,所以 J2SE 存根本身是很简单的。使用 Web 服务和使用本地类之间的惟一不同在于创建和使用远程服务的代理:

      // get a service stub
      Stub stub = createProxy();
      stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, 
        args[0]);

      // create the service
      InterSvc svc = (InterSvc) stub;

一旦 svc 对象创建好了,它就可以重复地用来获取远程对象。客户端的完整源代码如下所示:

package com.solutionst.wsiclient.test;

import javax.xml.rpc.Stub;
import com.solutionst.wsiclient.*;

public class WsiSimpleTest {

  public static void main(String[] args) {
    System.out.println("Endpoint address = " + args[0]);
    try {
      // get a service stub
      Stub stub = createProxy();
      stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, 
        args[0]);

      // create the service
      InterSvc svc = (InterSvc) stub;

      // say hello
      System.out.println("*** hello test");
      String helloResult = svc.sayHello("Interop developer");
      System.out.println("helloResult = " + helloResult);
      
      // get a part
      System.out.println("*** parts");
      PartArray pa = svc.getOnePart(12345);
      Part part[] = pa.getParts();
      System.out.println(
        "status code: " + Integer.toString(pa.getStatusCode()));
      System.out.println("msg: " + pa.getMsg());
      printOnePart(part[0]);
      // get a bad part
      pa = svc.getOnePart(1);
      // status code is negative
      System.out.println(
        "status code: " + Integer.toString(pa.getStatusCode()));
      System.out.println("msg: " + pa.getMsg());
      // search for parts
      pa = svc.findParts("widget");
      System.out.println(
        "status code: " + Integer.toString(pa.getStatusCode()));
      System.out.println("msg: " + pa.getMsg());
      Part parts[] = pa.getParts();
      System.out.println("Found many parts");
      for (int i = 0; i < parts.length; i++) {
        printOnePart(parts[i]);
      }

      // get an an assembly
      System.out.println("*** assemblies");
      AssemblyArray aa = svc.getOneAssembly(4321);
      System.out.println(
        "status code: " + Integer.toString(aa.getStatusCode()));
      System.out.println("msg: " + aa.getMsg());
      Assembly assembly[] = aa.getAssemblies();
      printOneAssy(assembly[0]);
      // search for assemblies
      aa = svc.findAssemblies("blivet");
      System.out.println(
        "status code: " + Integer.toString(aa.getStatusCode()));
      System.out.println("msg: " + aa.getMsg());
      System.out.println("Found many assemblies");
      Assembly assemblies[] = aa.getAssemblies();
      for (int i = 0; i < assemblies.length; i++) {
        printOneAssy(assemblies[i]);
      }

    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private static Stub createProxy() {
    // Note: MyHelloService_Impl is implementation-specific.
    return (Stub) (new InterSvcService_Impl().getInterSvc());
  }

  private static void printOnePart(Part pi) {

    System.out.println("Part: " + Integer.toString(pi.getPartId()));
    System.out.println("  Name:" + pi.getPartName());

  }
  private static void printOneAssy(Assembly assy) {

    System.out.println("Assembly: " + Integer.toString(assy.getAssemblyId()));
    System.out.println("  Assy name: " + assy.getAssemblyName());

    Part pi[] = assy.getParts();
    for (int i = 0; i < pi.length; i++) {
      printOnePart(pi[i]);
    }
  }

}

测试客户端

要测试客户端,您需要遵循下列步骤:

  1. 在 Java 编辑器中打开 Java 测试客户端。
  2. Run 菜单中选择 Run
  3. 高亮显示 Java Application 并按一下 New 按钮。
  4. Device Developer 将自动创建新的运行配置。选择 Arguments 选项卡并从 build.properties 文件中输入(或粘贴)服务端点地址作为惟一的程序参数。
  5. 按一下 Run 按钮以使用该应用程序。程序结果将显示在应用程序控制台窗口中。

应用程序 JAR 文件部署

在应用程序满足了您的需求之后,就可以使用 Device Developer 导出向导来将 JAR 文件导出到服务项目的 WebContent 目录中。在下一部分中,您将使用 Java Web Start 技术来部署应用程序 JAR 文件。

  1. 右键单击 WsiClient 项目并从弹出菜单中选择 Export
  2. 高亮显示 JAR file 并按 Next 以继续。
  3. JAR Export 对话框中,只选择 src 资源。选取 Export generate class files and resources 选项。按 Browse 按钮定位到服务器项目的 WebContent 目录。将导出的 JAR 文件命名为 testApp.jar。选取 compression 选项。
  4. Finish 以完成向导。

使用 Java Web Start 来开发客户端

修改服务器环境

本教程最后的一个重要步骤是创建用于应用程序开发的 Java Web Start 环境。Java Web Start(JWS)是这样的一项技术,它允许应用程序从中央服务器中部署而从客户端计算机中运行。JWS 在安全的 Applet 沙箱(sandbox)中运行应用程序,以便在保护客户端计算机的同时使应用程序能够自动从中央服务器中更新。

为了运行 Java Web Start 应用程序,服务器环境必须修改为使用 Java Web Start MIME 类型。

  1. 在服务器的 Device Developer 环境中,切换到 Server 透视图。
  2. 在 Device Developer 窗口的左下方,双击 Websphere 5.0 Test Environment server configuration 以编辑服务器配置。
  3. 选择 Web 选项卡以显示 Web Options
  4. Add 按钮来添加带有 JNLP 扩展的 application/x-java-jnlp-file MIME 类型。

  5. OK 来添加 MIME 类型。
  6. 保存(Save)并关闭服务器配置。

创建 Java Web Start Server 构件

部署 Web Start 应用程序的关键是将定义应用程序的 Java Network Launch Protocol(JNLP)文件部署到运行在客户端的 Java Web Start Application Manager。本教程中的应用程序的 JNLP 文件如下所示:

<?xml version="1.0" encoding="utf-8"?> 
<!-- JNLP File for Solutions TeleComputing InterOp Test Application --> 
<jnlp 
  spec="1.0+" 
  codebase="http://192.168.1.199:9080/WsiSvc" 
  href="testApp.jnlp"> 
  <information> 
    <title>Test Application</title> 
    <vendor>Solutions TeleComputing</vendor> 
    <homepage href="help.html"/> 
    <description>First Test Application</description> 
    <description kind="short">Test short description</description> 
    <offline-allowed/> 
  </information> 
  <security> 
      <all-permissions/> 
  </security> 
  <resources> 
    <j2se version="1.4"/> 
    <jar href="testapp.jar"/> 
    <extension name="Sun Jars" href="sunJars.jnlp"/>
  </resources> 
  <application-desc main-class="com.solutionst.wsiclient.test.WsiSimpleTest"> 
    <argument>http://192.168.1.199:9081/WsiSvc/services/InterSvc</argument>
  </application-desc>
</jnlp>
  • 代码基为 JNLP 文件中的未限定引用(href 元素)提供了 URL 前缀。JNLP 引用本身,这样客户端 Application Manager 就可以找到要测试的应用程序以进行更新。
  • offline allowed 元素告诉 Application Manager 服务器不是要运行的应用程序所需要的。
  • 安全性部分中的all-permissions 元素告诉客户端 Application Manager 允许这个应用程序访问所有的机器资源。您的应用程序可以有不同的安全性需求。
  • 在资源部分,J2SE 元素声明版本 1.4 是必需的,因为 Sun Web 服务的 JAR 文件需要 1.4 日志记录类。
  • jar 元素提供了指向应用程序的 testapp.jar 文件的 hreftestapp.jar 文件是本教程中的应用程序的中心。
  • extension 元素引用 sunJars.jnlp 文件。JNLP 规范要求 JNLP 资源中的所有 JAR 文件都设置为由同一认证机构进行签署,而 Sun Microsystems 已经签署了它们的 Web 服务 JAR。解决方案就是使应用程序 JNLP 需要定义 Sun Web 服务 JAR 文件的扩展。
  • application 元素定义程序的主类和参数。

testApp.jnlp 文件引用了 sunJars.jnlp 文件,以提供所需的 Sun Microsystems 公司的 JAR 文件给 JWS 客户端。sunJars.jnlp 文件的清单如下:

<?xml version="1.0" encoding="utf-8"?> 
<!-- JNLP File for Sun Web Service JAR files --> 
<jnlp 
  spec="1.0+" 
  codebase="http://192.168.1.199:9080/WsiSvc" 
  href="sunJars.jnlp"> 
  <information> 
    <title>Sun Jars</title> 
    <vendor>Sun Microsystems, Inc.</vendor> 
    <offline-allowed/> 
  </information> 
  <resources> 
    <j2se version="1.4"/> 
    <jar href="activation.jar"/> 
    <jar href="jax-qname.jar"/> 
    <jar href="jaxp-api.jar"/> 
    <jar href="jaxrpc-api.jar"/> 
    <jar href="jaxrpc-impl.jar"/> 
    <jar href="jaxrpc-spi.jar"/> 
    <jar href="mail.jar"/> 
    <jar href="saaj-api.jar"/> 
    <jar href="saaj-impl.jar"/> 
    <jar href="dom.jar"/> 
    <jar href="sax.jar"/> 
    <jar href="xalan.jar"/> 
    <jar href="xercesImpl.jar"/> 
    <jar href="xsltc.jar"/> 
  </resources> 
  <component-desc/>
</jnlp>

最后所需的 Web 服务器文件使 HTML 文件,以便引用 JNLP 文件并提供下载链接。在本教程中,我们是通过简单的 index.html 文件来引用 JNLP 文件的。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<LINK href="theme/Master.css" rel="stylesheet" type="text/css">
<TITLE>Test Application Java Web Start Home</TITLE>
</HEAD>
<BODY>

<H1>Test Java Web start</H1>
<P>Click <A href="testApp.jnlp">here</A> to install the app.</P>
</BODY>
</HTML>

index.html 文件的关键部分是指向 testApp.jnlphref。Java Web Start 的开发者文档提供了如何从您的 Web 站点动态安装 Java Web Start 的示例。

签署 JAR

支持本教程的实际应用程序需要访问客户端机器的硬盘,以便在服务器出现故障时存储状态信息。这种磁盘访问需求通过认证机构来数字化地签署应用程序使用的所有 JAR 文件成为必要。在本教程中,需要签署的惟一 JAR 是从客户端项目中导出的 testApp.jar 文件。

签署 JAR 最好从命令行中完成。在本教程中,您可以使用 J2SDK 1.4 附带的签署工具。下面的操作说明假定您运行的是 Windows 环境并且 Java bin 目录在您的命令路径中。

  1. 启动命令行程序。
  2. 创建一个目录来存储您的密钥和证书。
    md \keys
  3. 将命令行程序工作目录更改为服务器的 WebContent 目录。
  4. 创建一个新的的密钥和 keystore 并回答系统提示。您的密钥中提供的信息将出现在您的证书中(当它在客户端启动时)。不要忘记您指定的密码!
    keytool -genkey -keystore \keys\myKeystore -alias myself
  5. 创建一个自签署证书,您可以用这个证书来签署您的 JAR。
    keytool -selfcert -alias myself -keystore \keys\myKeystore
  6. 签署客户端 JAR 文件。您可能想要创建一个命令文件使 JAR 签署文件自动执行。
    jarsigner -keystore \keys\myKeystore testApp.jar myself

配置 Web Start

在测试您的简单应用程序之前,您需要配置客户端测试机器的 Java Web Start,以便在您的应用程序运行时显示 Java Console。要配置 Java Console,您需要遵循下列步骤:

  1. 在 Windows 桌面上双击 Java Web Start 图标以启动 JWS Application Manager。
  2. File 菜单中选择 Preferences
  3. 选择 Advanced 选项卡并选取 Show Java Console 选项。
  4. 按一下 OK 按钮以保存对 JWS 环境所作的更改并退出 JWS Application Manager。

测试 Web Start

测试本教程中的应用程序的最后一步是从浏览器调用 Java Web Start 应用程序并在 Java Console 中查看客户端结果。

  1. 启动您喜欢的浏览器并将其指向 WsiSvc/index.html 页面。.

  2. 单击 here 链接以安装和运行本教程中的应用程序。
  3. Security Warning 对话框出现时按一下 Start 按钮。

    在应用程序完成了下载和安装过程之后,客户端程序的输出将显示在控制台窗口中。

结束语

结束语

本教程完成了创建 Java 2 Standard Edition(J2SE)客户端来使用由 Application Server 提供的 Web 服务的过程。三个关键的开发步骤是:

  • 使用 Websphere Studio Application Developer 向导从简单的 Java Bean 创建 Websphere Web 服务。
  • 使用 Sun Java Web Services Developer Pack 工具来创建 J2SE Web 服务客户端。.
  • 使用 Java Web Ststar 从 Web 服务器部署客户端,以自动维护客户端配置。

参考资料

参考资料

本教程依赖于许多资源来完成它的工作。

  • 本教程中所用的代码可以在这里下载:ws-robustcode.zip
  • 可以从 java.sun.com 下载 Java 1.4.2 或更高版本的 Java 2 Software Development Kit(J2SDK)。
  • 客户端上的 Sun Java Runtime Environment(JRE)需要与从 java.sun.com 下载的 J2SDK 相匹配。
  • 可以从 IBM developerWorks 下载 IBM 的 Web Services Development Kit Version 5.1(WSDK V5.1)。
  • 可以从 java.sun.com 下载 Sun 的 Java Web Services Developer Pack Version 1.3(JWSDP 1.3)。

除了这些必需的资源之外,您还可能发现下面的链接是很有帮助的。


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=85106
ArticleTitle=健壮、可维护的客户端解决方案
publish-date=04052004