首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME HTTP 網路開發實戰範例:從 Servlet 到 MIDlet

     編輯:J2ME

早期 MIDP 1.0 裝置僅支援 HTTP 協定,所有網路功能(高分上傳、地圖下載、圖片獲取)皆仰賴 HTTP。本文提供完整的 Servlet 與 MIDlet 通訊範例,展示自訂協定設計與二進位資料傳輸技巧。

通訊協定設計

採用簡單的指令格式,例如:

  • GET|STRINGS|ID=5 — 請求文字資料
  • GET|PIC|ID=100 — 請求圖片二進位資料

伺服器回應對應的二進位資料流,客戶端解析處理。核心本質是「位元組流對位元組流」的操作。

伺服器端 Servlet

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]; }
}

客戶端 HTTP 工具類

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);
        }
    }
}

MIDlet 主程式

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 的情況(分塊讀取)
  • ✅ 實作連線逾時、重試、取消機制
  • ✅ 敏感資料傳輸使用 HTTPS
  • ✅ 釋放所有連線資源於 finally 區塊

擴展應用

此架構可輕鬆延伸至:

  • 遊戲地圖/關卡動態下載
  • 圖片/音效資源按需載入
  • 資料庫查詢/更新(透過 Servlet 存取 DB)
  • 即時排行榜、聊天訊息同步
  • 應用程式自動更新(下載 JAD/JAR)

掌握這套 HTTP 通訊範本,您就能開發出功能豐富、架構清晰的 J2ME 網路應用程式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved