创建新项目
您也许还记得,在第 1 部分中,一个 Eclipse 项目包含应用程序的源代码和其他相关文件。可以使用项目作为源代码容器,或者在项目中创建文件夹,以便组织文件。为了创建 Web 服务客户端,需要创建一个新的项目:
wsClientExample
,如图 2 所示。 src
文件夹,然后选择菜单项 New > Package,为客户端应用程序包输入一个名称,例如 com.myfirst.wsClient
,如图 4 所示。 生成 Web 服务客户端代码
为了创建客户端代码,需要运行 wsimport 任务。和在本系列第 1 部分中一样,您将从一个名为 build.xml
的 Ant 脚本中运行该任务:
build.xml
,然后单击 Finish(见图 5)。 <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> |
build.xml
文件之前,必须首先回到第 1 部分 中创建的项目,并启动 RunService 服务。为此,展开该项目,右键单击 RunService 文件,选择 Run As > Java Application。build.xml
文件,返回到本项目(wsClientExample),单击右键并选择 Run As > Ant Build,执行该 Ant 文件。BUILD SUCCESSFUL
消息,如图 7 所示。 在此过程中,wsimport 任务从运行 RunService 时发布的 WSDL 生成 JAX-WS 可移植工件。这就是服务必须首先运行的原因。
您将在下一节创建的客户端应用程序中使用这些生成的类。
创建客户端应用程序
现在,您已经生成了 Web 服务客户端的代码,接下来需要在 com.myfirst.wsClient 包下创建使用它的应用程序:
提供了含有一个类的包之后,便可以开始编写客户端代码,如清单 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
,并选择 Run As > Java Application。这时应该会显示 Eclipse IDE 控制台窗口。如果没有显示控制台窗口,从菜单栏选择 Window > Show View > Console。此时应该可以看到执行 Web 客户端的结果,如图 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 窗口中启动服务器和客户端应用程序:
build.xml
文件,在 Ant 编辑器中编辑它。 <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
,但首先会运行 pause。pause 任务依赖于 runServer
。这样便允许在客户端运行之前进行暂停,以便适当地启动服务器。所以 runServer
将首先运行。还有一点要注意的是 os
值。这个值表明将执行哪个操作系统(OS)命令,它由 Java Virtual Machine(JVM)决定。OS 是在os.name
系统属性中设置的。修改后的 build.xml
脚本只包括 Windows 和 Linux,但是必要时可以增加适合您环境的其他操作系统,并更改 Ant <exec> 任务。(请参阅 参考资料,了解更多关于 Ant 的信息)。
注意加粗的 <echo>
部分没有像其他行那样缩进。这是因为所有字符都会返回,包括空格字符。这意味着在 console 窗口中显示的消息将不会有前导空格(图 11)。当脚本运行时,它将显示可以从控制台运行的用于运行服务器应用程序的命令。
为了测试脚本的执行,可以对客户端应用程序作一些修改,以便可以运行它,直到退出。修改如下:
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
,选择 Run As > Ant Build。BUILD SUCCESSFUL
消息,如图 11 所示。 执行 Ant 脚本后,应该会打开两个命令窗口,一个是服务器应用程序的窗口(见图 12),一个是客户端应用程序的窗口(见图 13)。客户端窗口不断提示输入姓名,直到退出应用程序。每当输入一个姓名,修改后的 SayHelloClient 应用程序通过一个 while
循环进行迭代,在该循环中,它将输入的姓名发送到服务器,服务器则返回问候语,返回的问候语在窗口中显示为 Hello <name>。
在两个命令窗口中分别输入 “quit”,退出服务器和客户端 Java 应用程序,然后关闭每个命令窗口应用程序。
用 SOAP Monitor 监视通信
在 Eclipse 中配置 TCP/IP Monitor
至此,您已经创建了一个服务器和一个客户端,现在可以使用 Eclipse TCP/IP Monitor 监视 SOAP 传输。该监视器是一个简单的服务器,它监视服务器与客户端之间的所有请求和响应,如图 14 所示。
该视图将出现在 Eclipse IDE 底部的面板中,如图 16 所示。
从该窗口中(图 17),可以通过 Start 和 Stop 按钮管理表中列出的多个 TCP/IP 监视服务器。可以添加、编辑、移除、启动或停止可用的服务器。Status 列表明监视器是已启动还是已停止。
回页首
更新客户端代码
接下来,需要对客户端代码作一些更改,以便通过 TCP/IP monitor 重定向 Web 服务。这里需要更改 Web 服务的端点,因为 TCP/IP monitor 侦听端口 8081。更新后的代码如清单 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 类似:
在该视图中可以看到通过 TCP/IP Monitor 路由的请求和响应对。为了观察得更仔细,清单 6 和 7 显示了完整的头部:
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> |
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 服务服务器非常简单,只需使用 Eclipse 和 Java SE 6。借助过这些工具可以轻松地开发简单的 Web Services 服务器端和客户端应用程序。