在你开始前
关于本系列
本教程系列演示如何创建独立的Web服务服务器和客户端应用程序,您可以使用Java SE 6从命令行轻松地运行它们,而不是在Web应用程序服务器容器中运行。 使用一个简单的Hello World示例,您将利用Eclipse IDE,Java SE 6和Apache Ant轻松创建功能全面的Web服务服务器和客户端应用程序。 您还将使用TCP / IP监视器检查服务器和客户机之间的通信流量,并使用Eclipse Web Services Explorer工具测试Web Service。
关于本教程
本教程是该系列的第2部分,它描述了如何创建一个独立的Web服务客户端应用程序,以与您在第1部分中开发和部署的独立Web服务进行通信。 Eclipse IDE,Java SE 6和Ant来部署和部署Web服务客户端应用程序。
目标
完成本教程后,您应该知道:
- 如何使用Eclipse IDE创建Web服务的客户端,并使用Java SE 6生成和编译代码。
- 如何在Eclipse IDE中使用基于Ant Java的构建工具来运行特殊的Java命令,以从该系列的第1部分中发布的WSDL中生成一些代码。
- 如何在Eclipse IDE中使用TCP / IP监视器来观察,捕获和验证服务器和客户机之间Web服务的SOAP通信。
- 如何直接从Eclipse IDE外部的命令行运行服务器和客户端应用程序。
先决条件
本教程包括一些简单的步骤,这些步骤是为入门级到中级Java程序员编写的,它们具有Java语言和Ant构建的一些实用知识。 更高级的Java开发人员的新手将获得一些有关如何构建,部署和运行独立Web服务服务器和分布式客户端以提供防火墙友好的远程通信和应用程序处理的知识。
系统要求
要遵循示例,您需要下载:
- 面向Java EE开发人员的Eclipse IDE
- Java SE 6
您不必下载Ant,因为它的功能与Eclipse捆绑在一起。 本教程使用用于Java EE开发人员的Eclipse IDE的Ganymede软件包。
创建一个新项目
您可能从第1部分中回想起Eclipse项目包含应用程序的源代码和其他相关文件。 它使您可以将项目用作代码源容器,或在项目内部设置文件夹以组织文件。 您将需要创建一个新项目来构建Web服务客户端:
- 选择文件>新建>项目 。
- 展开Java文件夹,然后单击Java Project (参见图1)。
图1.在Eclipse中创建一个项目
- 单击下一步 。
- 出现提示时,输入一个项目名称,例如
wsClientExample
,如图2所示。
图2.在Eclipse中输入项目详细信息
- 如果先前默认情况下选择使用默认JRE单选按钮,则选择它;否则,请选择它。 否则, 请选择“ 使用项目特定的JRE”单选按钮,以确保它是Java SE 6。
- 单击完成,将您的项目与在第1部分中安装的Java JDK相关联。
- 如果系统提示您切换Java透视图,请单击是 。
现在,您的Eclipse环境应该在Package Explorer中列出了两个项目,如图3所示。一个项目将是您在本教程的第1部分中创建的一个项目,另一个将是您刚刚创建的一个项目。
图3. Eclipse中的Project Explorer
- 右键单击wsClientExample项目下的
src
文件夹,然后选择菜单选项New> Package,然后输入客户端应用程序包的名称,例如com.myfirst.wsClient
,如图4所示。
图4.在Eclipse中创建包
生成Web服务客户端代码
要创建客户端代码,您将需要运行wsimport任务。 与本系列的第一部分一样,您将从一个名为build.xml
的Ant脚本运行此脚本:
- 右键单击项目,然后选择“ 新建”>“文件” 。
- 输入名称
build.xml
,然后单击Finish (参见图5)。 - 通过右键单击该文件并选择“ 打开方式”>“ Ant编辑器 ”,确保使用Ant Editor打开该文件。 从现在开始,每当您双击该文件时,都应该使用Ant Editor打开它。
图5.创建build.xml文件
- 输入清单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>
- 在运行Ant
build.xml
文件之前,您必须首先返回在第1部分中创建的项目,并启动名为RunService的服务。 为此,请展开项目,然后右键单击RunService文件,然后选择Run As> Java Application 。 - 确保Eclipse IDE控制台窗口显示消息,说明服务已启动,如图6所示。
图6.运行服务的控制台
- 要运行Ant
build.xml
文件,请返回到该项目(wsClientExample),然后右键单击Run As> Ant Build ,以执行Ant文件。 - 确保这将导致在Eclipse Console窗口中
BUILD SUCCESSFUL
消息,如图7所示。
图7. Ant构建成功
- 返回Eclipse项目并通过右键单击wsClientExample并选择Refresh或通过突出显示该项目并按F5来刷新项目。 现在,您应该在新的包com.myfirst.wsClient下看到生成的代码来运行客户端(参见图8)。
图8.生成的代码
发生的事情是, wsimport任务从运行RunService时发布的WSDL生成了JAX-WS可移植工件。 这就是为什么该服务必须首先运行的原因。
- wsgen读取服务端点类并生成Web服务部署和调用所需的所有工件。
- wsimport读取WSDL并生成Web服务开发,部署和调用所需的所有工件。
您将在下一节中创建的Client应用程序中使用这些生成的类。
创建客户端应用程序
现在已经为Web Service的客户端生成了代码,您将需要创建将在com.myfirst.wsClient包下使用它的应用程序:
- 右键单击该软件包,然后选择选项New> Class,然后对其进行配置,如图9所示。
图9.创建一个类
- 使用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中运行它:
- 右键单击
SayHelloClient.java
然后选择运行方式> Java应用程序 。 应该显示Eclipse IDE控制台窗口。 如果不是,请转到菜单,然后选择选项窗口>显示视图>控制台 。 您应该看到执行Web Client的结果,如图10所示。
图10.运行客户端应用程序
运行SayHelloClient
应用程序时,它将创建一个新服务SayHelloService
,该服务是您通过清单1中的Ant脚本运行的wsimport任务生成的类之一。它随后获得端口SayHello
,该端口是要调用的代理目标服务端点上的操作。 然后,客户端获取请求上下文,并将端点地址http://localhost:8080/wsServerExample
到上下文,该上下文是用于处理请求消息的映射。 有两个打印语句,第一个以可读格式显示SayHello
,第二个显示返回问候Hello Fiona
(参见图10)。
完成后,可以通过在Eclipse控制台视图中终止Web服务来停止它。
使用脚本
要在没有Eclipse的情况下运行,可以修改wsClientExample的build.xml
以便在单独的外壳窗口中启动服务器和客户端应用程序:
- 双击
build.xml
文件以在Ant编辑器中对其进行编辑。 - 修改它,如清单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
具有两个新目标,即runServer
和runClient
。 您可能已经注意到,您还在第一行中更新了default
目标值,以便它不运行wsimport
任务,而是运行runClient
目标。 另外,请注意runClient
也与pause
有关,这意味着尽管默认值为runClient
,但它将首先暂停。 暂停任务取决于runServer
。 这样可以在客户端运行之前暂停一下,服务器才能正常启动。 因此, runServer
将首先运行。 另一个需要注意的是os
值。 这表明将执行哪个操作系统(OS)命令,并由Java虚拟机(JVM)确定。 操作系统在os.name
系统属性中设置。 修改后的build.xml
脚本仅包括Windows和Linux,但是您可以为您的环境添加适用的脚本,并根据需要更改Ant <exec>任务。 (请参阅参考资料以获取有关Ant的更多信息)。
请注意,以粗体显示的<echo>
部分与其他行不同。 这是因为回显了所有字符,包括任何空白字符。 这意味着在控制台窗口上,消息将没有前导空格(图11)。 运行脚本时,它将显示(回显)您可以从控制台运行的命令以运行服务器应用程序。
要测试脚本执行,可以选择对客户端应用程序进行一些修改,以便可以运行它直到退出为止,如下所示:
- 双击
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."); } }
客户端应用程序运行时,它将继续要求输入,直到输入quit
或exit
为止。 要运行Ant脚本:
- 右键单击
build.xml
,然后单击运行方式> Ant Build 。 - 确保这会导致在Eclipse Console窗口中
BUILD SUCCESSFUL
消息,如图11所示。
图11.蚂蚁构建成功并回显消息。
执行Ant脚本后,应启动两个命令窗口,一个用于服务器应用程序(请参见图12),另一个用于客户端应用程序(请参见图13)。 客户端窗口将要求您输入名称,直到您退出应用程序为止。 无论何时输入名称,修改后的SayHelloClient应用程序都会循环执行while
循环,在该循环中,您将输入的名称发送到返回问候语的服务器,显示为Hello <name> 。
图12.服务器的命令窗口
图13.客户端的命令窗口
通过在单独的命令窗口中键入“退出”来退出服务器和客户端Java应用程序,然后关闭每个命令窗口应用程序。
使用SOAP监视器监视通信
在Eclipse中配置TCP / IP监视器
现在,您已经创建了服务器和客户端,您可以使用Eclipse TCP / IP Monitor来监视SOAP通信。 监控器是一个简单的服务器,它监视在服务器和客户端之间流动的所有请求和响应,如图14所示。
图14.服务器和客户端SOAP通信
- 要查看此活动,您需要通过选择窗口>显示视图>其他>调试> TCP / IP监视器来打开TCP / IP监视器视图,如图15所示。
图15.显示TCP / IP监视器
该视图将出现在Eclipse IDE的底部窗格中,如图16所示。
图16.查看TCP / IP监视器
- 要配置TCP / IP Monitor,请选择Windows> Preferences,然后展开Run / Debug并单击TCP / IP Monitor ,如图17所示。
图17.添加TCP / IP监视器。
在此窗口(图17)中,您可以使用“ 开始”和“ 停止”按钮来管理表中列出的多个TCP / IP监视服务器。 您还可以添加,编辑,删除,启动或停止可用服务器。 “ 状态”列指示监视器是已启动还是已停止。
- 选中该框以在活动时显示“ TCP / IP监视器”视图,然后单击“ 添加...”按钮以定义一组新的配置选项,如图17所示。输入以下详细信息,如图18所示:
图18.配置TCP / IP监视器
选项说明- 本地监视端口是本地计算机上的唯一端口号,例如8081 。
- 主机名是用于运行服务器(例如localhost)的计算机的名称或IP地址。
- Port是远程服务器的端口号,例如8080 。
- 类型是从浏览器发送的请求类型,可以是HTTP或TCP / IP。
- 通信超时是指可以终止与服务器的TCP / IP连接之前的时间长度(以毫秒为单位)。
- 单击确定保存更改。
更新客户端代码
接下来,您将需要对客户端代码进行一些更改,以便通过TCP / IP监视器重定向Web服务。 由于TCP / IP监视器侦听端口8081 ,因此需要更改Web服务客户端的端点。 更新的代码如清单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监视器”视图,该视图应类似于下图,图19:
图19. TCP / IP监视器结果
您将看到通过TCP / IP监视器路由的显示请求和响应对。 为了更仔细地检查,清单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 。
可选活动
通过单击图18中用红色圆圈圈出的图标,可以确保Web服务SOAP流量符合WS-I。这将提示您保存一个日志文件,然后对该文件进行验证以确保符合性。 您可以在XML编辑器中打开此日志以检查其内容。
资料下载
下载适用于Java EE开发人员的Eclipse IDE 。
下载Java SE 6 。
附录:Web服务术语和缩写的简要概述
WS-I-Web服务的互操作性
WS-I是一个开放的行业组织,旨在促进跨平台,操作系统和编程语言的Web服务互操作性。
信封
信封是SOAP消息的一部分。 它定义了一个框架,用于描述消息中包含的内容以及如何对其进行处理。 SOAP消息是一个包含零个或多个标头和一个正文的信封。 它是XML文档的顶部元素,并提供控制信息,消息的地址以及消息本身的容器。
标头
标头传输任何控制信息。 它是信封的子元素。
身体
该主体包含消息标识及其参数。 它是信封的子元素。
摘要
创建,生成和发布Web服务服务器就像使用Eclipse以及Java SE 6一样简单。使用这些工具,您可以轻松开发简单的Web服务服务器和客户端。
翻译自: https://www.ibm.com/developerworks/webservices/tutorials/ws-jse/index.html