在 B/S 架構早期,Applet 作為富客戶端組件,常需與服務端 Servlet 進行數據交互。本文提供一個完整的「發送消息-接收回顯」示例,演示 Applet 如何通過 URLConnection 發起 HTTP 請求,Servlet 處理後返回響應,實現基礎的客戶端-服務端通信模型。
Applet,實現 ActionListener,構建 GUI(輸入框、發送按鈕、消息顯示區),使用 GridBagLayout 精確佈局。URL + URLConnection 模擬表單提交,關閉緩存,設置輸入流讀取響應。message 參數,處理後輸出文本,Applet 讀取並顯示在 messageText 中。import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
public class SendApplet extends Applet implements ActionListener {
// GUI 組件
Label sendLabel, messageInfo;
Button sendButton;
TextField sendText, messageText;
// 網絡通信
URLConnection connection;
String message;
URL servletBaseURL;
@Override
public String getAppletInfo() {
return "Applet-Servlet Communication Demo";
}
@Override
public synchronized void init() {
super.init();
resize(500, 300);
// 初始化組件
sendLabel = new Label("Please enter Message");
messageInfo = new Label("What you have sent:");
sendText = new TextField(40);
sendButton = new Button("Send");
messageText = new TextField(40);
messageText.setEditable(false);
// GridBagLayout 精細佈局
Panel mainPanel = new Panel();
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
mainPanel.setLayout(gbl);
// 第 0 行:提示標籤
gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 10; gbc.gridheight = 1;
gbc.anchor = GridBagConstraints.CENTER; gbc.fill = GridBagConstraints.NONE;
gbl.setConstraints(sendLabel, gbc);
mainPanel.add(sendLabel);
// 第 1 行:輸入框 + 按鈕
gbc.gridy = 1; gbc.gridwidth = 9; gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(sendText, gbc);
mainPanel.add(sendText);
gbc.gridx = 9; gbc.gridwidth = 1; gbc.fill = GridBagConstraints.NONE;
gbl.setConstraints(sendButton, gbc);
mainPanel.add(sendButton);
// 第 2 行:回顯標籤
gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 10;
gbl.setConstraints(messageInfo, gbc);
mainPanel.add(messageInfo);
// 第 3 行:回顯文本框(佔據剩餘空間)
gbc.gridy = 3; gbc.weighty = 100; gbc.gridheight = 10;
gbc.fill = GridBagConstraints.BOTH;
gbl.setConstraints(messageText, gbc);
mainPanel.add(messageText);
// 事件綁定與佈局生效
sendButton.addActionListener(this);
setLayout(new BorderLayout());
add("Center", mainPanel);
// 記錄 Servlet 基址(同源策略下通常為 Applet 所在服務器)
servletBaseURL = getCodeBase();
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == sendButton) {
sendMessage();
}
}
/** 核心發送邏輯 */
private void sendMessage() {
message = sendText.getText();
sendText.setText(""); // 清空輸入框
showStatus("Message send!");
messageText.setText("message"); // 臨時佔位
try {
// 構造查詢字符串:/servlet/Receive?message=URL編碼後內容
String queryString = "/servlet/Receive?message=" + URLEncoder.encode(message);
showStatus("Attempting to send: " + message);
// 建立連接
connection = new URL(servletBaseURL, queryString).openConnection();
showStatus("Open Connection!");
// 關鍵連接設置
connection.setDefaultUseCaches(false);
connection.setUseCaches(false);
connection.setDoInput(true); // 允許讀取響應
connection.setDoOutput(false); // GET 請求無需輸出流
connection.connect();
showStatus("Open Stream!");
DataInputStream in = new DataInputStream(connection.getInputStream());
showStatus("Reading...");
// 逐行讀取響應(此處僅保留最後一行)
String line;
while ((line = in.readLine()) != null) {
messageText.setText(line);
}
in.close();
} catch (MalformedURLException e2) {
System.err.println("MalformedURLException: " + e2);
} catch (IOException e1) {
System.err.println("IOException: " + e1);
}
}
// 生命週期佔位方法
public synchronized void start() {}
public synchronized void stop() {}
public synchronized void destroy() {}
}
用戶輸入可能包含空格、中文、特殊符號,必須進行 URL 編碼,否則 Servlet 接收到的參數會截斷或亂碼。對應服務端需用 URLDecoder.decode() 解碼。
| 方法 | 設置值 | 作用 |
|---|---|---|
| setUseCaches | false | 禁用瀏覽器/代理緩存,確保每次請求到達服務端 |
| setDoInput | true | 開啟輸入流讀取響應體 |
| setDoOutput | false | GET 請求無請求體,設為 false;POST 需設 true 並獲取 OutputStream |
網絡 I/O 會阻塞 AWT 事件分發線程(EDT),導致界面凍結。生產環境應將 sendMessage() 放入獨立線程或使用 SwingWorker(Swing 環境),Applet 可用 new Thread(this::sendMessage).start()。
Applet 只能連接其代碼來源(getCodeBase())的主機/端口。跨域需服務端配置 crossdomain.xml(舊 Flash 模式)或服務端代理轉發。
本示例展示了 Java 早期網絡編程的經典模式:Applet 作為有狀態客戶端,通過標準 HTTP 協議與 Servlet 交互。雖然技術棧已過時,但其中的 URLConnection 配置、流處理、異常捕獲、編碼規範等核心知識點,在當前的微服務調用、HTTP Client 開發中依然完全適用。