早期 MIDP 1.0 裝置僅支援 HTTP 協定,所有網路功能(高分上傳、地圖下載、圖片獲取)皆仰賴 HTTP。本文提供完整的 Servlet 與 MIDlet 通訊範例,展示自訂協定設計與二進位資料傳輸技巧。
採用簡單的指令格式,例如:
GET|STRINGS|ID=5 — 請求文字資料GET|PIC|ID=100 — 請求圖片二進位資料伺服器回應對應的二進位資料流,客戶端解析處理。核心本質是「位元組流對位元組流」的操作。
public class HttpGameServer extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int len = req.getContentLength();
System.out.println("Request length: " + len);
resp.setContentType("text/plain; charset=UTF-8");
try (DataInputStream dis = new DataInputStream(req.getInputStream());
PrintWriter out = resp.getWriter()) {
// 讀取客戶端指令
String cmd = dis.readUTF(); // 假設客戶端用 writeUTF
if ("GET_STRINGS".equals(cmd)) {
int id = dis.readInt();
String data = fetchStrings(id);
out.write(data);
} else if ("GET_PIC".equals(cmd)) {
int id = dis.readInt();
byte[] img = fetchImage(id);
resp.setContentType("image/png");
resp.getOutputStream().write(img);
}
} catch (Exception e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
private String fetchStrings(int id) { /* 從 DB/檔案讀取 */ return "Map Data " + id; }
private byte[] fetchImage(int id) { /* 讀取圖片檔 */ return new byte[0]; }
}
public class HttpClient {
private static final String UA = "Profile/MIDP-1.0 Configuration/CLDC-1.0";
public static byte[] post(String url, byte[] requestData) throws IOException {
HttpConnection conn = null;
InputStream is = null;
OutputStream os = null;
try {
conn = (HttpConnection) Connector.open(url);
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("User-Agent", UA);
conn.setRequestProperty("Content-Type", "application/octet-stream");
os = conn.openOutputStream();
if (requestData != null) os.write(requestData);
os.flush();
is = conn.openInputStream();
int rc = conn.getResponseCode();
if (rc != HttpConnection.HTTP_OK) throw new IOException("HTTP " + rc);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch;
while ((ch = is.read()) != -1) bos.write(ch);
return bos.toByteArray();
} finally {
closeQuietly(is);
closeQuietly(os);
closeQuietly(conn);
}
}
}
public class GameMIDlet extends MIDlet {
protected void startApp() {
new Thread() {
public void run() {
try {
// 請求地圖資料
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF("GET_STRINGS");
dos.writeInt(5);
dos.flush();
byte[] response = HttpClient.post(
"https://127.0.0.1:8080/examples/servlet/HttpGameServer",
bos.toByteArray()
);
// 解析回應
DataInputStream dis = new DataInputStream(
new ByteArrayInputStream(response));
String mapData = dis.readUTF();
// 更新 UI (需在事件執行緒)
Display.getDisplay(GameMIDlet.this).callSerially(() -> {
showMapScreen(mapData);
});
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
// ... pauseApp, destroyApp, showMapScreen 實作
}
// 下載圖片並建立 Image
byte[] imgData = HttpClient.post(imageUrl, null);
Image img = Image.createImage(imgData, 0, imgData.length);
// 下載大型資源顯示進度
HttpConnection conn = (HttpConnection) Connector.open(url);
long total = conn.getLength();
InputStream is = conn.openInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int read, progress = 0;
while ((read = is.read(buf)) != -1) {
bos.write(buf, 0, read);
if (total > 0) {
progress = (int)(bos.size() * 100 / total);
updateProgressBar(progress); // UI 回呼
}
}
DataOutputStream/DataInputStream 統一二進位格式User-Agent 讓伺服器識別客戶端版本Content-Length 為 -1 的情況(分塊讀取)finally 區塊此架構可輕鬆延伸至:
掌握這套 HTTP 通訊範本,您就能開發出功能豐富、架構清晰的 J2ME 網路應用程式。