内容


使用 Eclipse 和 Java SE 6 创建独立 Web Services 应用程序,第 2 部分

Web 服务客户端应用程序

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 使用 Eclipse 和 Java SE 6 创建独立 Web Services 应用程序,第 2 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:使用 Eclipse 和 Java SE 6 创建独立 Web Services 应用程序,第 2 部分

敬请期待该系列的后续内容。

开始之前

关于本系列

此系列教程演示如何使用 Java SE 6 创建可轻松地从命令行而不是从 Web 应用程序服务器容器中运行的独立 Web 服务服务端和客户端应用程序。在简单的 Hello World 示例中,您将利用 Eclipse IDE、Java SE 6 和 Apache Ant 轻松创建完全可以正常工作的 Web 服务服务端和客户端应用程序。您还将使用 TCP/IP Monitor 检查服务器与客户端之间的通信流量,并使用 Eclipse Web Services Explorer 工具测试 Web 服务。

关于本教程

本教程是本系列的第 2 部分,描述如何创建独立 Web 服务客户端应用程序,用于与第 1 部分中开发和部署的独立 Web 服务进行通信。本教程逐步讲解如何使用 Eclipse IDE、Java SE 6 和 Ant 开发和部署 Web 服务客户端应用程序。

目标

完成本教程后,您应该知道:

  • 如何通过使用 Eclipse IDE 生成代码,使用 Java SE 6 编译代码,创建 Web 服务的客户端。
  • 如何使用 Eclipse IDE 中基于 Java 的构建工具 Ant 运行专门的 Java 命令,从本系列第 1 部分发布的 WSDL 生成一些代码。
  • 如何使用 Eclipse IDE 中的 TCP/IP Monitor 观察、捕捉和验证服务器与客户机之间的 Web 服务 SOAP 传输。
  • 如何在 Eclipse IDE 外直接从命令行运行服务器和客户端应用程序。

先决条件

本教程包括为具备一些 Java 语言和 Ant 构建的实际应用知识的初级和中级 Java 程序员编写的简单步骤。初学者到更高级的 Java 开发人员将获得一些知识:学会如何构建、部署和运行独立 Web 服务服务端和分布式客户端,以提供防火墙友好的远程通信和应用程序处理。

系统需求

要按照示例进行操作,需要下载:

您不必下载 Ant,因为其功能与 Eclipse 打包在一起。本教程使用 Ganymede Package for the Eclipse IDE for Java EE Developers。

创建新项目

您也许还记得,在第 1 部分中,一个 Eclipse 项目包含应用程序的源代码和其他相关文件。可以使用项目作为源代码容器,或者在项目中创建文件夹,以便组织文件。为了创建 Web 服务客户端,需要创建一个新的项目:

  1. 选择 File > New > Project
  2. 展开 Java 文件夹并单击 Java Project(见图 1)。

    图 1. 在 Eclipse 中创建项目
    在 Eclipse 中创建项目
    在 Eclipse 中创建项目
  3. 单击 Next
  4. 根据提示输入项目名,例如 wsClientExample,如图 2 所示。

    图 2. 在 Eclipse 中输入项目详细信息
    在 Eclipse 中输入项目详细信息
    在 Eclipse 中输入项目详细信息
  5. 如果 Use default JRE 单选按钮之前已默认选中,则选择该单选按钮;否则选择 Use a project specific JRE 单选按钮,确保它是 Java SE 6。
  6. 单击 Finish 将项目与第 1 部分中安装的 Java JDK 相关联。
  7. 如果提示切换 Java 透视图,单击 Yes

    Eclipse 环境在 Package Explorer 中现在应该有两个项目,如图 3 所示。一个项目是在本教程第 1 部分中创建的,另一个项目是刚才创建的。

    图 3. Eclipse 中的 Project Explorer
    Eclipse 中的 Project Explorer
    Eclipse 中的 Project Explorer
  8. 右键单击 wsClientExample 项目下的 src 文件夹,然后选择菜单项 New > Package,为客户端应用程序包输入一个名称,例如 com.myfirst.wsClient,如图 4 所示。

    图 4. 在 Eclipse 中创建包
    在 Eclipse 中创建包
    在 Eclipse 中创建包

生成 Web 服务客户端代码

为了创建客户端代码,需要运行 wsimport 任务。和在本系列第 1 部分中一样,您将从一个名为 build.xml 的 Ant 脚本中运行该任务:

  1. 右键单击项目,选择 New > File
  2. 输入名称 build.xml,然后单击 Finish(见图 5)。
  3. 右键单击该文件,选择 Open With > Ant Editor,在 Ant Editor 中打开该文件。从现在起,每当双击该文件,都会在 Ant Editor 中打开它。

    图 5. 创建 build.xml 文件
    在 Eclipse 中创建项目
    在 Eclipse 中创建项目
  4. 输入清单 1 中显示的 Ant 项目。
    清单 1. Ant 脚本
    <project default="wsimport">
    
      <target name="wsimport">
        	
        <exec executable="{java.home}/../bin/wsimport">
        		
          <arg line="-keep -s ./src -p com.myfirst.wsClient 
              -d ./bin http://localhost:8080/wsServerExample?wsdl"/>
        		
        </exec>
        	
      </target>
    
    </project>
  5. 在运行 Ant build.xml 文件之前,必须首先回到第 1 部分 中创建的项目,并启动 RunService 服务。为此,展开该项目,右键单击 RunService 文件,选择 Run As > Java Application
  6. 确认 Eclipse IDE 控制台窗口显示消息说该服务已启动,如图 6 所示。

    图 6. 服务运行时的控制台
    服务运行时的控制台
    服务运行时的控制台
  7. 为了运行 Ant build.xml 文件,返回到本项目(wsClientExample),单击右键并选择 Run As > Ant Build,执行该 Ant 文件。
  8. 确认 Eclipse Console 窗口中显示一条 BUILD SUCCESSFUL 消息,如图 7 所示。

    图 7. Ant Build Success
    Ant Build Success
    Ant Build Success
  9. 返回到 Eclipse 项目,右键单击 wsClientExample 并选择 Refresh,或者选中项目并按 F5,刷新项目。现在在 com.myfirst.wsClient 包下应该可以看到生成的运行客户端的代码(见图 8)。

    图 8. 生成的代码
    生成的代码
    生成的代码

在此过程中,wsimport 任务从运行 RunService 时发布的 WSDL 生成 JAX-WS 可移植工件。这就是服务必须首先运行的原因。

  • wsgen 读取服务端点类,并生成部署和调用 Web 服务所需的所有工件。
  • wsimport 读取 WSDL,并生成开发、部署和调用 web 服务所需的所有工件。

您将在下一节创建的客户端应用程序中使用这些生成的类。

创建客户端应用程序

现在,您已经生成了 Web 服务客户端的代码,接下来需要在 com.myfirst.wsClient 包下创建使用它的应用程序:

  1. 右键单击那个包,选择选项 New > Class,然后配置它,如图 9 所示。

    图 9. 创建一个类
    创建一个类
    创建一个类
  2. 将类创建为 public,类中有一个 main 方法。

提供了含有一个类的包之后,便可以开始编写客户端代码,如清单 2 所示。

清单 2. 客户端应用程序
package com.myfirst.wsClient;

import javax.xml.ws.BindingProvider;

public class SayHelloClient {

    public static void main(String args[]) {
		
        SayHelloService shs = new SayHelloService();
		
        SayHello sh = (SayHello) shs.getSayHelloPort();
		
        ((BindingProvider)sh)。getRequestContext()。put(BindingProvider.
            ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8080/wsServerExample");

        System.out.println( ((BindingProvider)sh)。toString() );

        System.out.println(sh.getGreeting("Fiona"));

    }
}

运行客户端应用程序

使用 Eclipse

编写客户端应用程序之后,试着在 Eclipse 中运行它:

  1. 右键单击 SayHelloClient.java,并选择 Run As > Java Application。这时应该会显示 Eclipse IDE 控制台窗口。如果没有显示控制台窗口,从菜单栏选择 Window > Show View > Console。此时应该可以看到执行 Web 客户端的结果,如图 10 所示。

    图 10. 运行客户端应用程序
    运行客户端应用程序
    运行客户端应用程序

当运行 SayHelloClient 应用程序时,它创建一个新服务 SayHelloService,它是由通过清单 1 中的 Ant 脚本运行的 wsimport 任务生成的类之一。然后,它获得端口 SayHello,这是调用目标服务端点上的操作的一个代理。然后,该客户端获得请求上下文,将端点地址 http://localhost:8080/wsServerExample 添加到上下文,这个上下文是用于处理请求消息的一个 map。这里有两条 print 语句,第一条以易于阅读的格式显示 SayHello,第二条显示返回的问候语 Hello Fiona(见图 10)。

完成时,可以通过在 Eclipse console 视图中终止 Web 服务来停止它。

使用脚本

为了脱离 Eclipse 运行,可以修改 wsClientExample 的 build.xml,使它在单独的 shell 窗口中启动服务器和客户端应用程序:

  1. 双击 build.xml 文件,在 Ant 编辑器中编辑它。
  2. 修改该文件,如清单 3 所示。
    清单 3. 修改后的 build.xml 文件
    <project default="runClient">
    
        <!-- ================================= 
                target: wsimport              
             ================================= -->
        <target name="wsimport" description="--> 
                Read the WSDL and generate the required artifacts">
            <exec executable="${java.home}/../bin/wsimport">
                <arg line="-keep -s ./src -p com.myfirst.wsClient -d ./bin 
                    http://localhost:8080/wsServerExample?wsdl"/>
            </exec>
        </target>
    
        <!-- ================================= 
                target: runServer              
             ================================= -->
        <target name="runServer" description="--> 
                Runs the Web service server from a terminal">
            <echo>
    Running the following command from the terminal to run the server:
    ${java.home}/bin/java -cp "${basedir}/../wsServerExample/bin" 
        com.myfirst.wsServer.RunService
           </echo>
            
            <exec dir="${java.home}/bin/" executable="cmd" spawn="true" 
            		os="Windows XP" description="runs on XP">
                <arg line="start cmd /K start cmd /K" />
                <arg line='${java.home}/bin/java -cp 
                	"${basedir}/../wsServerExample/bin" 
                	com.myfirst.wsServer.RunService' />
            </exec>
            
            <exec executable="xterm" spawn="true" os="Linux" 
                    description="Runs on Linux">
                <arg line="-e ${java.home}/bin/java -cp  
                	'${basedir}/../wsServerExample/bin' 
                	com.myfirst.wsServer.RunService"/>
            </exec>
        </target>
    
        <!-- ================================= 
                target: pause
             ================================= -->
        <target name="pause" depends="runServer" description="--> 
                Pauses briefly while the server starts">
            <sleep seconds="5"/>
        </target>
    	
        <!-- ================================= 
                target: runClient
             ================================= -->
        <target name="runClient" depends="pause" description="--> 
                Runs a Web service client from a terminal">
            <echo>
    Running the following command from the terminal to run the client:
    ${java.home}/bin/java -cp "${basedir}/bin" com.myfirst.wsClient.SayHelloClient
           </echo>
    
            <exec dir="${java.home}/bin/" executable="cmd" spawn="true" 
                    os="Windows XP" description="Runs on XP">
                <arg line="start cmd /K start cmd /K" />
                <arg line='${java.home}/bin/java -cp "${basedir}/bin" 
                    com.myfirst.wsClient.SayHelloClient' />
            </exec>
            
            <exec executable="xterm" spawn="true" os="Linux" 
                    description="Runs on Linux">
                <arg line="-hold -e ${java.home}/bin/java -cp '${basedir}/bin' 
                    com.myfirst.wsClient.SayHelloClient" />
            </exec>
        </target>
    
    </project>

注意:若要在 linux 上运行,必须首先设置 JAVA_HOME;在命令行输入:set JAVA_HOME=<your/java/home>

新的 build.xml 有两个新的目标:runServerrunClient。您可能已经注意到,第一行中还更新了 default 目标值,使之不运行 wsimport 任务,而是运行 runClient 目标。而且,注意 runClientpause 有依赖,这意味着虽然默认值为 runClient,但首先会运行 pause。pause 任务依赖于 runServer。这样便允许在客户端运行之前进行暂停,以便适当地启动服务器。所以 runServer 将首先运行。还有一点要注意的是 os 值。这个值表明将执行哪个操作系统(OS)命令,它由 Java Virtual Machine(JVM)决定。OS 是在 os.name 系统属性中设置的。修改后的 build.xml 脚本只包括 Windows 和 Linux,但是必要时可以增加适合您环境的其他操作系统,并更改 Ant <exec> 任务。(请参阅 参考资料,了解更多关于 Ant 的信息)。

注意加粗的 <echo> 部分没有像其他行那样缩进。这是因为所有字符都会返回,包括空格字符。这意味着在 console 窗口中显示的消息将不会有前导空格(图 11)。当脚本运行时,它将显示可以从控制台运行的用于运行服务器应用程序的命令。

为了测试脚本的执行,可以对客户端应用程序作一些修改,以便可以运行它,直到退出。修改如下:

  1. 双击 SayHelloClient.java,编辑该文件,如以下清单所示:
    清单 4. 修改后的 SayHelloClient.java 文件
    package com.myfirst.wsClient;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    import javax.xml.ws.BindingProvider;
    import com.myfirst.wsClient.SayHello;
    import com.myfirst.wsClient.SayHelloService;
    
    public class SayHelloClient {
    
        public static void main(String[] args) {
    		
            SayHelloService shs = new SayHelloService();
            SayHello sh = (SayHello) shs.getSayHelloPort();
            ((BindingProvider) sh )。getRequestContext()。put(
                BindingProvider.ENDPOINT_ADDRESS_PROPERTY, 
                "http://localhost:8080/wsServerExample");
            System.out.println(((BindingProvider) sh)。toString());
    
            String userName = null;
            boolean exit = false;
            while (!exit) {
                System.out.print("\nPlease enter your name 
                    (type 'quit' to exit): ");
                BufferedReader br = new BufferedReader(
                    new InputStreamReader(System.in));
                try {
                    userName = br.readLine();
                } catch (IOException e) {
                    System.out.println("Error reading name.");
                    System.exit(1);
                }
                if (!(exit = userName.trim()。equalsIgnoreCase("quit") || 
                        userName.trim()。equalsIgnoreCase("exit"))) {
                    System.out.println(sh.getGreeting(userName));
                }
            }
            System.out.println("\nThank you for running the client.");
        }
    }

当客户端应用程序运行时,它将继续提示输入,直到输入 quitexit。为了运行 Ant 脚本:

  1. 右键单击 build.xml,选择 Run As > Ant Build
  2. 确认 Eclipse Console 窗口出现一条 BUILD SUCCESSFUL 消息,如图 11 所示。

    图 11. Ant 构建成功的消息以及返回的消息
    Ant 构建成功的消息以及返回的消息
    Ant 构建成功的消息以及返回的消息

执行 Ant 脚本后,应该会打开两个命令窗口,一个是服务器应用程序的窗口(见图 12),一个是客户端应用程序的窗口(见图 13)。客户端窗口不断提示输入姓名,直到退出应用程序。每当输入一个姓名,修改后的 SayHelloClient 应用程序通过一个 while 循环进行迭代,在该循环中,它将输入的姓名发送到服务器,服务器则返回问候语,返回的问候语在窗口中显示为 Hello <name>

图 12. 服务器的命令窗口
服务器的命令窗口
服务器的命令窗口
图 13. 客户端的命令窗口
客户端的命令窗口
客户端的命令窗口

在两个命令窗口中分别输入 “quit”,退出服务器和客户端 Java 应用程序,然后关闭每个命令窗口应用程序。

用 SOAP Monitor 监视通信

在 Eclipse 中配置 TCP/IP Monitor

至此,您已经创建了一个服务器和一个客户端,现在可以使用 Eclipse TCP/IP Monitor 监视 SOAP 传输。该监视器是一个简单的服务器,它监视服务器与客户端之间的所有请求和响应,如图 14 所示。

图 14. 服务器与客户端之间的 SOAP 传输
服务器与客户端之间的 SOAP 传输
服务器与客户端之间的 SOAP 传输
  1. 要查看该活动,需要选择 Window > Show View > Other > Debug > TCP/IP Monitor,从而打开 TCP/IP Monitor 视图,如图 15 所示。

    图 15. 显示 TCP/IP Monitor
    显示 TCP/IP Monitor

该视图将出现在 Eclipse IDE 底部的面板中,如图 16 所示。

图 16. 查看 TCP/IP Monitor
查看 TCP/IP Monitor
查看 TCP/IP Monitor
  1. 要配置 TCP/IP Monitor,可选择 Windows > Preferences,并展开 Run/Debug,然后单击 TCP/IP Monitor,如图 17 所示。

    图 17. 添加 TCP/IP Monitor
    添加 TCP/IP Monitor
    添加 TCP/IP Monitor

从该窗口中(图 17),可以通过 StartStop 按钮管理表中列出的多个 TCP/IP 监视服务器。可以添加、编辑、移除、启动或停止可用的服务器。Status 列表明监视器是已启动还是已停止。

  1. 勾选窗口中的复选框,以便每当有活动时自动显示 TCP/IP Monitor 视图,然后单击 Add... 按钮定义一组新的配置选项,如图 17 所示。输入以下详细信息,如图 18 所示:

    图 18. 配置 TCP/IP Monitor
    配置 TCP/IP Monitor
    配置 TCP/IP Monitor



    选项描述
    • Local monitoring port 是本地计算机上一个唯一的端口号,例如 8081
    • Host name 是用于运行服务器的计算机的计算机名或 IP 地址,例如 localhost
    • Port 是远程服务器的端口号,例如 8080
    • Type 是从浏览器发送的请求类型,有 HTTP 和 TCP/IP 两种选项。
    • Communication Timeout 是与服务器的 TCP/IP 连接可持续的时间长度,单位为毫秒。
  1. 单击 OK 保存更改。

更新客户端代码

接下来,需要对客户端代码作一些更改,以便通过 TCP/IP monitor 重定向 Web 服务。这里需要更改 Web 服务的端点,因为 TCP/IP monitor 侦听端口 8081。更新后的代码如清单 5 所示:

清单 5. 客户端应用程序
package com.myfirst.wsClient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.xml.ws.BindingProvider;
import com.myfirst.wsClient.SayHello;
import com.myfirst.wsClient.SayHelloService;

public class SayHelloClient {

    public static void main(String[] args) {
		
        SayHelloService shs = new SayHelloService();
        SayHello sh = (SayHello) shs.getSayHelloPort();
        ((BindingProvider) sh )。getRequestContext()。put(
            BindingProvider.ENDPOINT_ADDRESS_PROPERTY, 
            "http://localhost:8081/wsServerExample");
        System.out.println(((BindingProvider) sh)。toString());

        String userName = null;
        boolean exit = false;
        while (!exit) {
            System.out.print("\nPlease enter your name 
                (type 'quit' to exit): ");
            BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in));
            try {
                userName = br.readLine();
            } catch (IOException e) {
                System.out.println("Error reading name.");
                System.exit(1);
            }
            if (!(exit = userName.trim()。equalsIgnoreCase("quit") || 
                    userName.trim()。equalsIgnoreCase("exit"))) {
                System.out.println(sh.getGreeting(userName));
            }
        }
        System.out.println("\nThank you for running the client.");
    }
}

运行 Web 服务

再次运行 Ant 脚本:右键单击之前创建的用于运行服务器和客户端的 build.xml,并选择 Run As > Ant Build

此时再次出现两个命令窗口,一个是服务器窗口,一个是客户端窗口。和之前一样,输入姓名。

查看 TCP/IP Monitor 视图,该视图看上去应该和下面的图 19 类似:

图 19. TCP/IP Monitor 的结果
TCP/IP Monitor 的结果
TCP/IP Monitor 的结果

在该视图中可以看到通过 TCP/IP Monitor 路由的请求和响应对。为了观察得更仔细,清单 6 和 7 显示了完整的头部:

清单 6. 请求头部
POST /wsServerExample HTTP/1.1
SOAPAction: ""
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-Type: text/xml; charset=utf-8
User-Agent: Java/1.6.0
Host: localhost:8081
Connection: keep-alive
Content-Length: 226

<?xml version="1.0" encoding="UTF-8"?>
  <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Body>
    <ns2:getGreeting xmlns:ns2="http://wsServer.myfirst.com/">
      <arg0>Fiona</arg0>
    </ns2:getGreeting>
  </S:Body>
  </S:Envelope>
清单 7. 响应头部
HTTP/1.1 200 OK
Content-type: text/xml; charset=utf-8
Transfer-encoding: chunked

fc
<?xml version="1.0" encoding="UTF-8"?>
  <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Body>
    <ns2:getGreetingResponse xmlns:ns2="http://wsServer.myfirst.com/">
      <return>Hello Fiona</return>
    </ns2:getGreetingResponse>
  </S:Body>
  </S:Envelope>
0

可以看到,请求头部信封中加粗的部分是在客户端应用程序的命令窗口中输入的内容,此处为 Fiona。现在看看响应头部信封,可以看到返回的响应,此处为 Hello Fiona

可选活动

可以通过单击图 19 中用红色圈住的图标,确认 Web 服务 SOAP 传输是否遵从 WS-I。这将提示您保存一个日志文件,之后要验证该文件是否遵从 WS-I。可以在 XML 编辑器中打开该日志,查看它的内容。

附录:Web 服务术语和缩略语概述

WS-I - Web 服务互操作性组织(Web services interoperability)

WS-I 是一个开发的行业组织,专门促进 Web 服务跨平台、操作系统和编程语言的互操作性。

Envelope(信封)

Envelope 是 SOAP 消息的一部分。它定义一个框架,以描述消息中的内容以及如何处理消息。SOAP 消息就是一个 Envelope,由 0 个或多个头部和一个主体组成。Envelope 是 XML 文档的顶层元素,是控制信息、消息地址和消息本身的容器。

Headers(头部)

头部包含所有的控制信息。它是 Envelope 的子元素。

Body(主体)

主体包含消息的身份信息及其参数。它是 Envelope 的子元素。

结束语

创建、生成和发布 Web 服务服务器非常简单,只需使用 Eclipse 和 Java SE 6。借助过这些工具可以轻松地开发简单的 Web Services 服务器端和客户端应用程序。


相关主题


评论

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services, Java technology, Open source
ArticleID=465710
ArticleTitle=使用 Eclipse 和 Java SE 6 创建独立 Web Services 应用程序,第 2 部分: Web 服务客户端应用程序
publish-date=02012010