通过 Web 服务传递二进制数据,第 6 部分:创建 Swing 客户端
下载样例
本练习的目的在于为您以前创建和部署的 Web 服务创建一个客户端,然后给该客户端添加一个 GUI 界面。该界面显示 Web 服务以二进制数据传递的图像。
本教程中的课程

- 概述
- 创建 EJB 模块
- 创建 Web 服务
- 测试 Web 服务
- 修改架构文件和 WSDL 文件以传递二进制数据
- => 创建 Swing 客户端
创建 Swing 客户端
在以下步骤中,会创建一个 Web 应用程序。在此应用程序内,将创建一个客户端,该客户端使用您在以前的教程中创建并修改的 Web 服务。然后向该 Web 应用程序添加一个 JFrame,并在其中使用 Swing 组件设计一个 GUI 界面。最后,将该 Swing 组件绑定到该 Web 服务客户端代码。
创建 Swing 客户端:
- 选择“文件”>“新建项目”(Ctrl-Shift-N)。此时将打开“新建项目 ”向导。选择 Java 类别中的“Java 应用程序”选项。单击“下一步”。此时将打开“新建 Java 应用程序”向导。在“项目名称”中键入 FlowerClient 并单击“完成”。IDE 创建一个新的 Java 应用程序项目。
- 右键单击 FlowerClient 项目节点,然后从上下文菜单选择“新建”>“Web 服务客户端”。此时将打开“新建 Web 服务客户端”向导。选择 WSDL URL 单选按钮,并将 WSDL 文件的 URL 粘贴到该字段。默认情况下,该 URL 为 http://localhost:8080/FlowerService/FlowerService?WSDL。单击“完成”。IDE 将下载该 WSDL 文件,添加与 Web 服务交互的客户端桩模块,并在“项目”窗口的 Java 应用程序项目中添加节点,如下所示。

- 右键单击 "FlowerClient" 节点,然后选择“新建”>“JFrame 窗体”。将该窗体命名为 FlowerFrame。并且,将其置于 flowerclient 包中。
- 向该 FlowerFrame 添加一个 JPanel。对其进行扩展,以填充整个 FlowerFrame。将该面板命名为 gardenFlowersPanel。
- 将以下 Swing 组件添加到 gardenFlowersPanel,从面板的顶部开始。(有关 Swing 组件的教程,请参见 在 NetBeans IDE 中设计 Swing GUI):
- Label。变量名:titleLabel,文本:Garden Flowers,位置:顶部居中。您可能想要将文本设置为粗体和/或增大字号。
- ButtonGroup。变量名:buttonGroup1。
- 将以下 4 个单选按钮添加到 titleLabel 下面的水平行中。在每个按钮的属性中,将其设置为 buttonGroup1 的成员。
| asterRadioButton |
true |
Aster |
| honeysuckleRadioButton |
false |
Honeysuckle |
| roseRadioButton |
false |
Rose |
| sunflowerRadioButton |
false |
Sunflower |
- JScrollPane。变量名:mainScrollPane。位置:在单选按钮下,填充水平空间和大约三分之二的剩余垂直空间。
- JPanel。变量名:mainPanel。布局:边框式。位置:填充 mainScrollPane。
- JButton。变量名:mainPictureButton。文本:Waiting for picture... 位置:在 mainPanel 中(根据面板的边框式布局,按钮将自动填充整个空间)。
- JScrollPane。变量名:thumbnailScrollPane。位置:在单选按钮下,填充水平空间和所有剩余的垂直空间。
- JPanel。变量名:thumbnailPanel。布局:网格式。位置:填充 thumbnailScrollPane。网格式布局表示以下 4 个按钮将会是同样大小,并完全填充 thumbnailPanel。
| asterButton |
Waiting... |
| honeysuckleButton |
Waiting... |
| roseButton |
Waiting |
| sunflowerButton |
Waiting... |
此时,FlowerFrame 将如下所示。

- 在源代码编辑器中,像这样初始化 FlowerFrame:
public static final String[] FLOWERS = {"aster", "honeysuckle", "rose", "sunflower"};
private Map<String, Image> flowers;
public FlowerFrame(Map<String, Image> flowers) {
this.flowers = flowers;
for (String flower:FLOWERS) {
flowers.put(flower,null);
}
initComponents();
setTitle("Garden Flowers [waiting for picture]");
ItemListener rbListener = new RBListener();
asterRadioButton.addItemListener(rbListener);
honeysuckleRadioButton.addItemListener(rbListener);
roseRadioButton.addItemListener(rbListener);
sunflowerRadioButton.addItemListener(rbListener);
ActionListener bListener = new ButtonListener();
asterButton.addActionListener(bListener);
honeysuckleButton.addActionListener(bListener);
roseButton.addActionListener(bListener);
sunflowerButton.addActionListener(bListener);
}
- 当单击 JRadioButton 时,我们希望在主按钮中显示一个新图像。
private class RBListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
showFlower();
}
}
void showFlower() {
Image img = null;
if (asterRadioButton.isSelected()) {
img = flowers.get("aster");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Aster]");
}
} else if (honeysuckleRadioButton.isSelected()) {
img = flowers.get("honeysuckle");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Honeysuckle]");
}
} else if (roseRadioButton.isSelected()) {
img = flowers.get("rose");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Rose]");
}
} else if (sunflowerRadioButton.isSelected()) {
img = flowers.get("sunflower");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Sunflower]");
}
}
if (img == null) {
mainPictureButton.setIcon(null);
setTitle("Garden Flowers [waiting for picture]");
} else mainPictureButton.setText("");
}
- 当单击 JButton 时,我们选择相关的 JRadioButton:
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == asterButton) asterRadioButton.setSelected(true);
else if (e.getSource() == honeysuckleButton) honeysuckleRadioButton.setSelected(true);
else if (e.getSource() == roseButton) roseRadioButton.setSelected(true);
else if (e.getSource() == sunflowerButton) sunflowerRadioButton.setSelected(true);
}
}
- 在 Main 类中,将会调用 FlowerFrame 中的 setThumbnails 方法。
void setThumbnails(Map<String, Image> thumbs) {
Image img = thumbs.get("aster");
if (img != null) {
asterButton.setIcon(new ImageIcon(img));
asterButton.setText("");
}
img = thumbs.get("honeysuckle");
if (img != null) {
honeysuckleButton.setIcon(new ImageIcon(img));
honeysuckleButton.setText("");
}
img = thumbs.get("rose");
if (img != null) {
roseButton.setIcon(new ImageIcon(img));
roseButton.setText("");
}
img = thumbs.get("sunflower");
if (img != null) {
sunflowerButton.setIcon(new ImageIcon(img));
sunflowerButton.setText("");
}
}
- 在 FlowerFrame 中修复导入(如果在代码中粘贴导入内容时未对其进行修复)。通过在编辑器中单击鼠标右键,然后从上下文菜单中选择“修复导入”,可以一次性修复所有导入内容。下面是完整的导入语句集:
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Map;
import javax.swing.ImageIcon;
- 按如下所示填充 Main.java 类。
public class Main {
private static int downloadedPictures;
public static void main(String[] args) {
final Map<String,Image> flowers = new HashMap<String,Image>(4);
final Map<String,Image> thumbs = new HashMap<String,Image>(4);
// Show the FlowerFrame.
final FlowerFrame frame = new FlowerFrame(flowers);
frame.setVisible(true);
// The client connects to the service with this code.
FlowerService_Service service = new FlowerService_Service();
final FlowerService port = service.getFlowerServicePort();
Runnable[] tasks = new Runnable[4];
// The web service getFlower operation
// is called 4 times, each in a separate thread.
// When the operation finishes the picture is shown in
// a specific button.
for (int i=0; i<4;i++) {
final int index = i;
tasks[i] = new Runnable() {
public void run() {
try {
// Call the getFlower operation
// on the web service:
Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
// Add strings to the hashmap:
flowers.put(FlowerFrame.FLOWERS[index],img);
// Call the showFlower operation
// on the FlowerFrame:
frame.showFlower();
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
downloadedPictures++;
}
};
new Thread(tasks[i]).start();
}
// The web service getThumbnails operation is called
// in a separate thread, just after the previous four threads finish.
// When the images are downloaded, the thumbnails are shown at
// the bottom of the frame.
Runnable thumbsTask = new Runnable() {
public void run() {
try {
while (downloadedPictures < 4) {
try {Thread.sleep(100);} catch (InterruptedException ex) {}
}
// Call the getThumbnails operation
// on the web service:
List<Image> images = port.getThumbnails();
System.out.println("thumbs downloaded");
if (images != null && images.size() == 4) {
for (int i=0;i<4;i++) {
thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
}
frame.setThumbnails(thumbs);
}
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
}
};
new Thread(thumbsTask).start();
}
}
- 在 Main.java 中修复导入(如果在代码中粘贴导入内容时未对其进行修复)。通过在编辑器中单击鼠标右键,然后从上下文菜单中选择“修复导入”,可以一次性修复所有导入内容。您可以选择要导入的 List 类;请选择 java.util.List。下面是完整的导入语句集:
import flower.album.FlowerService;
import flower.album.FlowerService_Service;
import flower.album.IOException_Exception;
import java.awt.Image;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
- 删除 FlowerFrame 类中的现有 main 方法。
现在该 Web 服务完整了,具有与 Web 服务交互的代码,该 Web 服务委托给了 EJB 模块,以公开其图像。右键单击客户端,然后选择“运行”。将启动 Swing 应用程序,并且之后会填充从 Web 服务接收到的图像。如果图像没有全部出现,请清理并生成 FlowerService 项目,然后再次运行。
后续步骤:
Logging and Optimizing the Service(登录和优化服务)
要发送意见和建议、获得支持以及随时了解 NetBeans IDE Java EE 开发功能的最新开发情况,请加入 nbj2ee@netbeans.org 邮件列表。