blob: 41cf17d505c8cfc08ad3e6eadfc1bb4d4a3c99d6 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= 开发 JAX-WS Web 服务客户端
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: 开发 JAX-WS Web 服务客户端 - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, 开发 JAX-WS Web 服务客户端
在本教程中,您将使用 NetBeans IDE 提供的 Web 服务工具来分析拼写检查器 Web 服务,然后构建一个与该服务交互的 Web 客户端。该客户端使用一个 Servlet 类和 Web 页。用户将信息从 Web 页传送到 Servlet
image::images/netbeans-stamp-80-74-73.png[title="此页上的内容适用于 NetBeans IDE 7.2、7.3、7.4 和 8.0"]
*要学习本教程,您需要具备以下软件和资源。*
|===
|软件或资源 |要求的版本
|link:https://netbeans.org/downloads/index.html[+NetBeans IDE+] |Java EE 下载包
|link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+Java 开发工具包 (JDK)+] |版本 7 或版本 8
|符合 Java EE 规范的 Web 服务器或应用服务器 |Tomcat Web Server 7.0
GlassFish Server Open Source Edition
Oracle WebLogic Server
|===
*注:*如果使用的是 JDK 6,则需要 JDK 6 Update 7 或更高版本。
Tomcat GlassFish Server 都可以随同 NetBeans IDE Web Java EE 分发一起安装。此外,也可以访问 link:https://glassfish.java.net/download.html[+GlassFish Server 下载页+]或 link:http://tomcat.apache.org/download-60.cgi[+Apache Tomcat 下载页+]。
*重要说明:*Java EE 项目需要使用 Tomcat 7.xGlassFish Server Oracle WebLogic Server 12c
下面显示了您将创建的客户端的外观,其中的所有数据都是从 Web 服务接收到的:
image::images/jaxwsc-spellchecker-report.png[title="拼写检查器报告"]
当学完本教程时,您会发现对于此应用程序,您只需提供要检查的文本,调用 Web 服务上的操作以及呈现结果。IDE 会生成联系 Web 服务以及发送文本所需的全部代码。其余的操作则由拼写检查器 Web 服务来完成。它将标识拼错的单词并提供建议的替代项列表。
本教程中使用的拼写检查器 Web 服务是由 link:http://www.cdyne.com/account/home.aspx[+CDYNE 公司+]提供的。CDYNE 旨在开发、销售并支持一整套数据增强、数据质量和数据分析 Web 服务以及商业智能集成。拼写检查器 Web 服务是 CDYNE 提供的一个 Web 服务。请注意,基于一个或多个 Web 服务的应用程序的功能大小取决于这些 Web 服务的可用性和可靠性。但是,CDYNE 在link:http://www.cdyne.com/company/faqs.aspx[+常见问题解答+]中指出,它有一个 100% 可用性目标,并且在发生自然灾害、恐怖行为或其他灾难性事件时,Web 服务流量会传输到其辅助数据中心。CDYNE 在编写本教程以及开发 NetBeans 方面给予了大力支持,NetBeans 要在此特别向其表示感谢。
== 使用拼写检查器 Web 服务
要通过网络使用名为 "consuming" Web 服务,需要创建一个 Web 服务客户端。为了便于创建 Web 服务客户端,NetBeans IDE 提供了一个客户端创建工具,即“Web 服务客户端”向导,利用该向导可以生成用于查找 Web 服务的代码。此外,IDE 还提供了用于对所创建的 Web 服务客户端进行开发的工具,即 "Projects"(项目)窗口中包含节点的工作区域。这些工具包含在 NetBeans IDE 安装的 EE 包中。这些工具为即用型,无需任何插件。
=== 创建客户端
在此部分,您将利用向导生成基于 Web 服务 WSDL 文件的 Java 对象。
1. 选择 "File"(文件)> "New Project"(新建项目)(在 Windows Linux 中为 Ctrl-Shift-N 组合键,在 MacOS 上为 ⌘-Shift-N 组合键)。在 "Categories"(类别)下,选择 "Java Web"。在 "Projects"(项目)下选择 "Web Application"Web 应用程序)。单击 "Next"(下一步)。将项目命名为 ``SpellCheckService`` ,然后确保将相应的服务器指定为目标服务器。(有关详细信息,请参考“入门指南”一节。)将其他所有选项保留为默认设置,然后单击 "Finish"(完成)。
2. "Projects"(项目)窗口中,右键单击 ``SpellCheckService`` 项目节点,选择 "New"(新建)> "Other"(其他),然后在 "New File"(新建文件)向导的 "Web Services"Web 服务)类别中选择 "Web Service Client"Web 服务客户端)。单击 "Next"(下一步)。
3. 选择 "WSDL URL" 并为 Web 服务指定以下 URL
link:http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl[+http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl+]
如果您处于防火墙的保护下,可能需要指定代理服务器,否则将无法下载 WSDL 文件。要指定代理服务器,请在向导中单击 "Set Proxy"(设置代理)。IDE "Options"(选项)窗口将会打开,在此可为 IDE 设置普遍接受的代理。
[start=4]
. 将包名保留为空。默认情况下,将从 WSDL 中获取客户端类包名。在本例中为 ``com.cdyne.ws`` 。单击 "Finish"(完成)。
[start=5]
. "Projects"(项目)窗口的 "Web Service References"Web 服务引用)节点中,您将看到以下内容:
image::images/ws-refs.png[title="显示 Web 服务引用的 "Projects"(项目)窗口"]
"Projects"(项目)窗口显示了一个名为 "check" Web 服务,可以对应用程序执行多次 "CheckTextBody" "CheckTextBodyV2" 操作。这些操作用于检查字符串是否存在拼写错误,并返回要由客户端处理的数据。该服务的 V2 版本不需要身份验证。在本教程中,将使用 ``checkSoap.CheckTextBodyV2`` 操作。
``Generated Sources`` (生成的源文件)节点中,您将看到由 JAX-WSWeb 服务客户端”向导生成的客户端桩模块。
image::images/gen-files.png[title="显示构建节点的包结构的文件视图"]
展开 "WEB-INF" 节点及其 "wsdl" 子节点。您将看到 WSDL 文件的本地副本,其名称为 ``check.asmx.wsdl``
image::images/web-inf.png[]
用于创建客户端的 WSDL URL 已在 ``jax-ws-catalog.xml`` 中映射到 WSDL 的本地副本。映射到本地副本有几个好处。首先,客户端无需 WSDL 的远程副本即可运行。其次,客户端运行速度将会加快,因为其不需要对远程 WSDL 文件进行解析。最后,更加易于移植。
image::images/jax-ws-catalog.png[]
=== 开发客户端
您可以通过多种方法来实现 Web 服务客户端。Web 服务的 WSDL 文件限制了您可以向该 Web 服务发送的信息类型,以及您从该 Web 服务接收的信息类型。但是,WSDL 文件不限制您对其所需信息进行传递的_方式_,以及用户界面所包含的_内容_。您接下来要构建的客户端实现包含一个 Web 页和一个 Servlet,前者可使用户输入要检查的文本,后者可将这些文本传递至 Web 服务,然后构建一个包含结果的报告。
==== 编码 Web
Web 页将包含一个文本区域和一个按钮,前者可供用户输入文本,后者用于将该文本发送至 Web 服务。根据您选择作为目标服务器的服务器版本不同,IDE 生成了 ``index.html`` ``index.jsp`` 作为应用程序的索引页。
1. "Projects"(项目)窗口中,展开 ``SpellCheckService`` 项目的 "Web Pages"Web 页)节点,然后双击索引页( ``index.html`` ``index.jsp`` )以在源代码编辑器中打开文件。
2. 将以下代码复制并粘贴到索引页的 ``<body>`` 标记中:
[source,html]
----
<body>
<form name="Test" method="post" action="SpellCheckServlet">
<p>Enter the text you want to check:</p>
<p>
<p><textarea rows="7" name="TextArea1" cols="40" ID="Textarea1"></textarea></p>
<p>
<input type="submit" value="Spell Check" name="spellcheckbutton">
</form>
</body>
----
上面列出的代码指定当单击提交按钮时, ``textarea`` 的内容将被发送至名为 ``SpellCheckServlet`` Servlet
==== 创建 Servlet 并对其进行编码
在此部分,您将创建一个与 Web 服务交互的 Servlet。但是,执行交互的代码将由 IDE 提供。因此,您只需处理业务逻辑,即,准备要发送的文本以及对结果进行处理。
1. "Projects"(项目)窗口中,右键单击 ``SpellCheckService`` 项目节点,选择 "New"(新建)> "Other"(其他),然后选择 "Web" > "Servlet"。单击 "Next"(下一步)以打开 "New Servlet"(新建 Servlet)向导。
2. Servlet 命名为 ``SpellCheckServlet`` ,然后在 "Package"(包)下拉列表中键入 ``clientservlet`` 。单击 "Next"(下一步)。
image::images/name-servlet.png[]
[start=3]
. "Configure Servlet Deployment"(配置 Servlet 部署)面板中,注意此 Servlet URL 映射是 ``/SpellCheckServlet`` 。接受默认值,然后单击 "Finish"(完成)。该 Servlet 将在源代码编辑器中打开。
image::images/jaxwsc-servlet.png[]
[start=4]
. 将光标置于源代码编辑器中的 ``SpellCheckServlet.java`` ``processRequest`` 方法主体内,并在该方法的顶部添加一些新行。
[start=5]
. 右键单击上一步所创建的空白区域,然后选择 "Insert Code"(插入代码)> "Call Web Service Operation"(调用 Web 服务操作)。在 "Select Operation to Invoke"(选择要调用的操作)对话框中,单击 ``checkSoap.CheckTextBodyV2`` 操作,如下所示:
image::images/insert-ws-ops.png[title="显示 Web 服务引用的 "Projects"(项目)窗口"]
单击 "OK"(确定)。
*注:*您也可以将此操作节点直接从 "Projects"(项目)窗口拖放至编辑器中,而不调用以上所示的对话框。
``SpellCheckServlet`` 类的末尾,将会看到一个用于调用 SpellCheckerV2 服务并返回 ``com.cdyne.ws.DocumentSummary`` 对象的私有方法。
[source,java]
----
private DocumentSummary checkTextBodyV2(java.lang.String bodyText) {com.cdyne.ws.CheckSoap port = service.getCheckSoap();return port.checkTextBodyV2(bodyText);}
----
只需使用此方法即可调用 Web 服务上的操作。此外,还需在类的顶部声明以下代码行(粗体显示):
[source,java]
----
public class SpellCheckServlet extends HttpServlet {
*@WebServiceRef(wsdlLocation = "http://wsf.cdyne.com/SpellChecker/check.asmx?WSDL")
private Check service;*
----
[start=6]
. ``processRequest()`` 方法的 ``try`` 块替换为以下代码。以下代码行中的注释说明了每行代码的用途。
[source,html]
----
try (PrintWriter out = response.getWriter()) {
* //Get the TextArea from the web page*String TextArea1 = request.getParameter("TextArea1");*//Initialize WS operation arguments*
java.lang.String bodyText = TextArea1;
*//Process result*
com.cdyne.ws.DocumentSummary doc = checkTextBodyV2(bodyText);
String allcontent = doc.getBody();
*//From the retrieved document summary,
//identify the number of wrongly spelled words:*
int no_of_mistakes = doc.getMisspelledWordCount();
*//From the retrieved document summary,
//identify the array of wrongly spelled words:*
List allwrongwords = doc.getMisspelledWord();
out.println("<html>");
out.println("<head>");
*//Display the report's name as a title in the browser's titlebar:*
out.println("<title>Spell Checker Report</title>");
out.println("</head>");
out.println("<body>");
*//Display the report's name as a header within the body of the report:*
out.println("<h2><font color='red'>Spell Checker Report</font></h2>");
*//Display all the content (correct as well as incorrectly spelled) between quotation marks:*
out.println("<hr><b>Your text:</b> \"" + allcontent + "\"" + "<p>");
*//For every array of wrong words (one array per wrong word),
//identify the wrong word, the number of suggestions, and
//the array of suggestions. Then display the wrong word and the number of suggestions and
//then, for the array of suggestions belonging to the current wrong word, display each
//suggestion:*
for (int i = 0; i < allwrongwords.size(); i++) {
String onewrongword = ((Words) allwrongwords.get(i)).getWord();
int onewordsuggestioncount = ((Words) allwrongwords.get(i)).getSuggestionCount();
List allsuggestions = ((Words) allwrongwords.get(i)).getSuggestions();
out.println("<hr><p><b>Wrong word:</b><font color='red'> " + onewrongword + "</font>");
out.println("<p><b>" + onewordsuggestioncount + " suggestions:</b><br>");
for (int k = 0; k < allsuggestions.size(); k++) {
String onesuggestion = (String) allsuggestions.get(k);
out.println(onesuggestion);
}
}
*//Display a line after each array of wrong words:*
out.println("<hr>");
*//Summarize by providing the number of errors and display them:*
out.println("<font color='red'><b>Summary:</b> " + no_of_mistakes + " mistakes (");
for (int i = 0; i < allwrongwords.size(); i++) {
String onewrongword = ((Words) allwrongwords.get(i)).getWord();
out.println(onewrongword);
}
out.println(").");
out.println("</font>");
out.println("</body>");
out.println("</html>");
}
----
[start=7]
. 您会看到许多错误线和警告图标,指示未找到的类。要在粘贴代码之后修复导入,请按 Ctrl-Shift-I 组合键(在 Mac 上按 ⌘-Shift-I 组合键),或在任意位置单击鼠标右键,然后在打开的上下文菜单中选择 "Fix Imports"(修复导入)。(您可以选择要导入的 List 类。此处将接受默认的 java.util.List。)以下是已导入类的完整列表:
[source,java]
----
import com.cdyne.ws.Check;
import com.cdyne.ws.Words;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.WebServiceRef;
----
*注:*如果看到“找不到 ``com.cdyne.*`` 类”的警告内容,请不要担心。当构建项目后,IDE 在解析 WSDL 文件并查找类时,此问题会得到解决。
请注意,尚未处理上面列出的代码中存在的错误。有关详细信息,请参见<<applyingwhatyouhavelearned,应用所学知识>>。
=== 部署客户端
IDE 使用 Ant 构建脚本来构建和运行应用程序。此构建脚本是由 IDE 基于您在创建项目时所输入的选项来构建的。您可以在项目的 "Project Properties"(项目属性)对话框(在 "Projects"(项目)窗口中右键单击项目节点,然后选择 "Properties"(属性))中调整这些选项。
1. 右键单击项目节点,然后选择 "Run"(运行)。稍后,应用程序将部署并显示上一部分所编码的 Web 页。
2. 输入一些文本,确保其中的某些文本存在拼写错误:
image::images/jaxwsc-spellchecker-form.png[title="带有要检查文本的 JSP 页"]
[start=3]
. 单击 "Spell Check",然后查看结果:
image::images/jaxwsc-spellchecker-report.png[title="显示错误的拼写检查器报告"]
[[asynch]]
== 异步 Web 服务客户端
默认情况下,NetBeans IDE 创建的 JAX-WS 客户端是同步的。同步客户端会调用对服务的请求,然后在等待响应时挂起其处理。但是,在某些情况下,您希望客户端继续一些其他处理而不是等待响应。例如,在某些情况下,服务可能需要大量时间来处理请求。继续处理而不等待服务响应的 Web 服务客户端称为“异步”。
异步客户端会发出服务请求,然后继续其处理而不等待响应。服务会处理客户端请求,然后在一段时间后返回响应,而客户端则在这段时间内检索响应并继续其处理。
异步客户端会通过“轮询”或“回调”方法使用 Web 服务。在“轮询”方法中,将调用一个 Web 服务方法并反复请求结果。“轮询”是一种阻止操作,因为它会阻止调用线程,所以这就是不在 GUI 应用程序中使用它的原因。在“回调”方法中,您在 Web 服务方法调用期间传递回调处理程序。当结果有效时,将调用该处理程序的 ``handleResponse()`` 方法。这种方法适用于 GUI 应用程序,因为您不必等待响应。例如,从 GUI 事件处理程序发出调用并立即返回控制权,这样可以使用户界面随时保持响应。轮询方法的缺点是,即使在捕获响应后使用响应,也必须对其进行轮询来查明已将其捕获。
NetBeans IDE 中,通过勾选 Web 服务引用的编辑 Web 服务属性 GUI 中的框,将异步客户端的支持添加到 Web 服务客户端应用程序中。除了具有轮询 Web 服务或传递回调处理程序并等待结果的方法外,开发该客户端的所有其他方面都与同步客户端相同。
此部分的其余内容详述了如何创建 Swing 图形界面并将异步 JAX-WS 客户端嵌入其中。
[[asynch-swing]]
=== 创建 Swing 窗体
在此部分,您将设计 Swing 应用程序。如果不愿意自己设计 Swing GUI,可以link:https://netbeans.org/projects/www/downloads/download/webservices%252FAsynchSpellCheckForm.zip[+下载预先设计的 JFrame+],然后转至<<asynch-creatingtheclient,创建异步客户端>>中的此部分内容。
Swing 客户端会获取您键入的文本,将其发送至服务,然后返回错误数和所有错误词语的列表。该客户端还会向您显示每个错误词语和替换该词语的建议,一次只显示一个错误词语。
image::images/asynch-swing-client.png[]
*创建 Swing 客户端:*
1. 创建新的 Java 应用程序项目。将其命名为 ``AsynchSpellCheckClient`` 。不要为该项目创建 ``Main`` 类。
2. "Projects"(项目)视图中,右键单击 ``AsynchSpellCheckClient`` 项目节点并选择 "New"(新建)> "JFrame Form..."JFrame 窗体...)。
3. 将该窗体命名为 ``MainForm`` ,然后将其放置在包 ``org.me.forms`` 中。
4. 创建 JFrame 后,打开项目属性。在 "Run"(运行)类别中,将 ``MainForm`` 设置为主类。
image::images/asynch-main-class.png[]
[start=5]
. 在编辑器中,打开 ``MainForm.java`` "Design"(设计)视图。在组件面板中,将三个滚动窗格拖放至 ``MainForm`` 中。定位滚动窗格并调整其大小。这些窗格将包含要进行检查所键入的文本、所有错误词语以及对某个错误词语提出的建议的文本字段。
[start=6]
. 将五个文本字段拖放至 ``MainForm`` 中。将其中的三个拖放至三个滚动窗格中。按如下方式对其进行修改:
|===
|文本字段
|变量名称 |在滚动窗格中? |可编辑?
|tfYourText |Y |Y
|tfNumberMistakes |N |N
|tfWrongWords |Y |N
|tfWrongWord1 |N |N
|tfSuggestions1 |Y |N
|===
[start=7]
. 将进度栏拖放至 ``MainForm`` 中。将该变量命名为 ``pbProgress``
[start=8]
. 将两个按钮拖放至 ``MainForm`` 中。将第一个按钮命名为 ``btCheck`` ,并将其文本更改为 "Check Text" "Check Spelling"。将第二个按钮命名为 ``btNextWrongWord`` ,将其文本更改为 "Next Wrong Word",然后禁用该按钮。
[start=9]
. 将一些标签拖放至 ``MainForm`` 中,为应用程序提供一个标题并描述文本字段。
JFrame 的外观按您喜欢的方式进行排列,然后进行保存。接下来将添加 Web 服务客户端功能。
[[asynch-creatingtheclient]]
=== 启用异步客户端
如<<creatingtheclient,创建客户端>>中所述,添加 Web 服务引用。然后编辑 Web 服务属性以启用异步客户端。
1. "Projects"(项目)窗口中,右键单击 ``AsynchSpellCheckClient`` 项目节点,然后选择 "New"(新建)> "Other"(其他)。在新建文件向导中,选择 "Web Services"Web 服务)> "Web Service Client"Web 服务客户端)。在“Web 服务客户端”向导中,指定 Web 服务的 URL
link:http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl[+http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl+]。接受所有默认值,然后单击 "Finish"(完成)。这与<<creatingtheclient,创建客户端>>中所述步骤 2 以后的过程相同。
[start=2]
. 展开 "Web Service References"Web 服务引用)节点,然后右键单击 ``check`` 服务。上下文菜单打开。
image::images/asynch-edit-ws-attrib.png[]
[start=3]
. 从上下文菜单中选择 "Edit Web Service Attributes"(编辑 Web 服务属性)。“Web 服务属性”对话框打开。
[start=4]
. 选择 "WSDL Customization"WSDL 定制”)签。
[start=5]
. 展开 "Port Type Operations"(端口类型操作)节点。展开*第一个* ``CheckTextBodyV2`` 节点并选择 "Enable Asynchronous Client"(启用异步客户端)。
image::images/enable-async-client.png[]
[start=6]
. 单击 "OK"(确定)。该对话框关闭,并出现一条警告,指出更改 Web 服务属性将会刷新客户端节点。
image::images/asynch-refresh-node-warning.png[]
[start=7]
. 单击 "OK"(确定)。该警告信息关闭,并刷新客户端节点。如果展开 "Web Service References"Web 服务引用)中的 ``check`` 节点,则会看到现在已具有 ``CheckTextBody`` 操作的 "Polling"(轮询)和 "Callback"(回调)版本。
image::images/asynch-ws-refs.png[]
现已为您的应用程序启用了 SpellCheck 服务的异步 Web 服务客户端。
[[asynch-addcode]]
=== 添加异步客户端代码
现在,您已经有了异步 Web 服务操作,可将其中一个异步操作添加到 ``MainForm.java`` 中。
*添加异步客户端代码:*
1. ``MainForm`` 中,切换到 "Source"(源)视图,然后将以下方法添加到最后一个右花括号的前面。
[source,java]
----
public void callAsyncCallback(String text){
}
----
[start=2]
. "Projects"(项目)窗口中,展开 ``AsynchSpellCheckClient`` "Web Service References"Web 服务引用)节点,并找到 ``checkSoap.CheckTextBodyV2 [Asynch Callback]`` 操作。
[start=3]
. ``CheckTextBodyV2 [Asynch Callback]`` 操作拖至空的 ``callAsyncCallback`` 方法主体中。IDE 会生成以下 ``try`` 块。将此生成的代码与为同步客户端生成的代码进行比较。
[source,java]
----
try { // Call Web Service Operation(async. callback)
com.cdyne.ws.Check service = new com.cdyne.ws.Check();
com.cdyne.ws.CheckSoap port = service.getCheckSoap();
// TODO initialize WS operation arguments here
java.lang.String bodyText = "";
javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler =
new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {
public void handleResponse(javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
try {
// TODO process asynchronous response here
System.out.println("Result = "+ response.get());
} catch(Exception ex) {
// TODO handle exception
}
}
};
java.util.concurrent.Future<? extends java.lang.Object> result = port.checkTextBodyV2Async(bodyText, asyncHandler);
while(!result.isDone()) {
// do something
Thread.sleep(100);
}
} catch (Exception ex) {
// TODO handle custom exceptions here
}
----
在此代码与 Web 服务调用中,您会看到来自 SpellCheck 服务的响应是通过 ``AsynchHandler`` 对象进行处理的。同时, ``Future`` 对象会查看是否已返回了结果,然后使线程休眠直至完全返回了结果。
[start=4]
. 切换回 "Design"(设计)视图。双击 "Check Spelling" 按钮。IDE 会自动将 "ActionListener" 添加到按钮中,然后切换到 "Source"(源)视图中,光标同时出现在空的 ``btCheckActionPerformed`` 方法中。
[start=5]
. 将以下代码添加至 ``btCheckActionPerformed`` 方法主体。此代码会获取您在 ``tfYourText`` 字段中键入的文本,使进度栏显示 "waiting for server" 消息,并禁用 ``btCheck`` 按钮,以及调用异步回调方法。
[source,java]
----
private void btCheckActionPerformed(java.awt.event.ActionEvent evt) {
*String text = tfYourText.getText();
pbProgress.setIndeterminate(true);
pbProgress.setString("waiting for server");
btCheck.setEnabled(false);
callAsyncCallback(text);*
}
----
[start=6]
. ``MainForm`` 类的开头,实例化名为 ``nextWord`` 的私有 ``ActionListener`` 字段。此 ``ActionListener`` 字段是为 Next Wrong Word 按钮提供的,使用该按钮可以前进到错误词语列表中的下一个错误词语,并显示该词语以及更正它的建议。您可以在此处创建私有字段,这样就可以在定义了 ``ActionListener`` 的情况下取消对其的注册。否则,每次检查新文本时,都将添加一个额外的监听程序并最终出现多个监听程序多次调用 ``actionPerformed()`` 的情况。这样,该应用程序将无法正常运行。
[source,java]
----
public class MainForm extends javax.swing.JFrame {
private ActionListener nextWord;
...
----
[start=7]
. 将整个 ``callAsyncCallback`` 方法替换为以下代码。请注意,最外层的 ``try`` 块已删除。此代码块是多余的,因为已在方法内添加了更多特定的 ``try`` 块。并且在代码注释中介绍了对代码所做的其他更改。
[source,java]
----
public void callAsyncCallback(String text) {
com.cdyne.ws.Check service = new com.cdyne.ws.Check();
com.cdyne.ws.CheckSoap port = service.getCheckSoap();
// initialize WS operation arguments here
java.lang.String bodyText = text;
javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler = new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {
public void handleResponse(final javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
// Create a DocumentSummary object containing the response.
// Note that getDocumentSummary() is called from the Response object
// unlike the synchronous client, where it is called directly from
// com.cdyne.ws.CheckTextBodycom.cdyne.ws.DocumentSummary doc = response.get().getDocumentSummary();
//From the retrieved DocumentSummary,
//identify and display the number of wrongly spelled words:
final int no_of_mistakes = doc.getMisspelledWordCount();
String number_of_mistakes = Integer.toString(no_of_mistakes);
tfNumberMistakes.setText(number_of_mistakes);
// Check to see if there are any mistakes
if (no_of_mistakes > 0) {
//From the retrieved document summary,
//identify the array of wrongly spelled words, if any:
final List<com.cdyne.ws.Words> allwrongwords = doc.getMisspelledWord();
//Get the first wrong word
String firstwrongword = allwrongwords.get(0).getWord();
//Build a string of all wrong words separated by commas, then display this in tfWrongWords
StringBuilder wrongwordsbuilder = new StringBuilder(firstwrongword);
for (int i = 1; i < allwrongwords.size(); i++) {
String onewrongword = allwrongwords.get(i).getWord();
wrongwordsbuilder.append(", ");
wrongwordsbuilder.append(onewrongword);
}
String wrongwords = wrongwordsbuilder.toString();
tfWrongWords.setText(wrongwords);
//Display the first wrong word
tfWrongWord1.setText(firstwrongword);
//See how many suggestions there are for the wrong word
int onewordsuggestioncount = allwrongwords.get(0).getSuggestionCount();
//Check to see if there are any suggestions.
if (onewordsuggestioncount > 0) {
//Make a list of all suggestions for correcting the first wrong word, and build them into a String.
//Display the string of concactenated suggestions in the tfSuggestions1 text field
List<String> allsuggestions = ((com.cdyne.ws.Words) allwrongwords.get(0)).getSuggestions();
String firstsuggestion = allsuggestions.get(0);
StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion);
for (int i = 1; i < onewordsuggestioncount; i++) {
String onesuggestion = allsuggestions.get(i);
suggestionbuilder.append(", ");
suggestionbuilder.append(onesuggestion);
}
String onewordsuggestions = suggestionbuilder.toString();
tfSuggestions1.setText(onewordsuggestions);
} else {
// No suggestions for this mistake
tfSuggestions1.setText("No suggestions");
}
btNextWrongWord.setEnabled(true);
// See if the ActionListener for getting the next wrong word and suggestions
// has already been defined. Unregister it if it has, so only one action listener
// will be registered at one time.
if (nextWord != null) {
btNextWrongWord.removeActionListener(nextWord);
}
// Define the ActionListener (already instantiated as a private field)
nextWord = new ActionListener() {
//Initialize a variable to track the index of the allwrongwords list
int wordnumber = 1;
public void actionPerformed(ActionEvent e) {
if (wordnumber < no_of_mistakes) {
// get wrong word in index position wordnumber in allwrongwords
String onewrongword = allwrongwords.get(wordnumber).getWord();
//next part is same as code for first wrong word
tfWrongWord1.setText(onewrongword);
int onewordsuggestioncount = allwrongwords.get(wordnumber).getSuggestionCount();
if (onewordsuggestioncount > 0) {
List<String> allsuggestions = allwrongwords.get(wordnumber).getSuggestions();
String firstsuggestion = allsuggestions.get(0);
StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion);
for (int j = 1; j < onewordsuggestioncount; j++) {
String onesuggestion = allsuggestions.get(j);
suggestionbuilder.append(", ");
suggestionbuilder.append(onesuggestion);
}
String onewordsuggestions = suggestionbuilder.toString();
tfSuggestions1.setText(onewordsuggestions);
} else {
tfSuggestions1.setText("No suggestions");
}
// increase i by 1
wordnumber++;
} else {
// No more wrong words! Disable next word button
// Enable Check button
btNextWrongWord.setEnabled(false);
btCheck.setEnabled(true);
}
}
};
// Register the ActionListener
btNextWrongWord.addActionListener(nextWord);
} else {
// The text has no mistakes
// Enable Check button
tfWrongWords.setText("No wrong words");
tfSuggestions1.setText("No suggestions");
tfWrongWord1.setText("--");
btCheck.setEnabled(true);
}
} catch (Exception ex) {
ex.printStackTrace();
}
// Clear the progress bar
pbProgress.setIndeterminate(false);
pbProgress.setString("");
}
});
}
};
java.util.concurrent.Future result = port.checkTextBodyV2Async(bodyText, asyncHandler);
while (!result.isDone()) {
try {
//Display a message that the application is waiting for a response from the server
tfWrongWords.setText("Waiting...");
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
----
[start=8]
. Ctrl-Shift-I 组合键(在 Mac 上按 ⌘-Shift-I 组合键)并修复导入。这样会添加以下 import 语句:
[source,java]
----
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
----
现在,您可以构建并运行应用程序了!遗憾的是,您不可能在获取服务器响应的很长延迟时间里看到所发生的变化,因为服务的处理速度相当快。
== 应用所学知识
现在,您已在 IDE 中创建了第一个 Web 服务客户端,接下来该您大显身手,对应用程序进行全方位扩展了。下面建议了两项可着手执行的任务。
* Servlet 中添加错误处理代码。
* 重写客户端,以使用户可与从 Web 服务返回的数据进行交互。
link:/about/contact_form.html?to=3&subject=Feedback:%20JAX-WS%20Clients%20in%20NetBeans%20IDE[+发送有关此教程的反馈意见+]
== 另请参见
有关使用 NetBeans IDE 开发 Java EE 应用程序的更多信息,请参见以下资源:
* link:jax-ws.html[+JAX-WS Web 服务入门指南+]
* link:rest.html[+REST 风格的 Web 服务入门指南+]
* link:wsit.html[+Advanced Web Service Interoperability+](高级 Web 服务互操作性)
* link:../../trails/web.html[+Web 服务学习资源+]
要发送意见和建议、获得支持以及随时了解 NetBeans IDE Java EE 开发功能的最新开发情况,请link:../../../community/lists/top.html[+加入 nbj2ee@netbeans.org 邮件列表+]。