經典三層架構在 J2ME 專案中的落地:
[J2ME MIDlet] <-- HTTP + DataInput/OutputStream --> [Servlet (Tomcat)] <-- JDBC-ODBC Bridge --> [Access .mdb]
本文提供從環境建置、MIDlet 端、Servlet 端、資料庫設定到部署驗證的完整步驟。
test.mdb,資料表 user:欄位 id (自動編號)、name (文字)。public class NetMain extends MIDlet implements CommandListener {
private Display display;
private Form mainForm;
private Command connectCmd = new Command("連線查詢", Command.OK, 1);
public NetMain() { display = Display.getDisplay(this); }
protected void startApp() {
mainForm = new Form("J2ME 聯網測試");
mainForm.append("點擊下方按鈕向 Servlet 發送查詢請求");
mainForm.addCommand(connectCmd);
mainForm.setCommandListener(this);
display.setCurrent(mainForm);
}
public void commandAction(Command c, Displayable d) {
if (c == connectCmd) {
display.setCurrent(new SendMsgForm(this));
}
}
// pauseApp, destroyApp, exit 略...
}
public class SendMsgForm extends Form implements CommandListener, Runnable {
private static final String SERVLET_URL = "https://localhost:8080/returnMsg";
private Thread connThread;
private NetMain parent;
private Command exitCmd = new Command("返回", Command.BACK, 1);
public SendMsgForm(NetMain parent) {
super("查詢結果");
this.parent = parent;
append("正在連線伺服器...");
addCommand(exitCmd);
setCommandListener(this);
connThread = new Thread(this);
connThread.start();
}
public void run() {
try {
String result = sendHttpGet(SERVLET_URL);
// 在事件執行緒更新 UI
Display.getDisplay(parent).callSerially(() -> {
deleteAll();
append(result);
});
} catch (IOException e) {
Display.getDisplay(parent).callSerially(() -> {
deleteAll();
append("連線失敗: " + e.getMessage());
});
}
}
private String sendHttpGet(String url) throws IOException {
HttpConnection conn = null;
DataInputStream dis = null;
StringBuffer sb = new StringBuffer();
try {
conn = (HttpConnection) Connector.open(url);
dis = new DataInputStream(conn.openInputStream());
String line;
// 注意:Servlet 端使用 writeUTF,需配合 readUTF 讀取
while ((line = dis.readUTF()) != null) {
sb.append(line).append("\n");
}
} finally {
if (dis != null) dis.close();
if (conn != null) conn.close();
}
return sb.toString();
}
public void commandAction(Command c, Displayable d) {
if (c == exitCmd) parent.exit();
}
}
public class returnMsg extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("application/octet-stream"); // 二進位串流
ServletOutputStream out = res.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 載入 JDBC-ODBC Bridge 驅動 (JDK 內建)
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:mydata");
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT id, name FROM user");
dos.writeUTF("=== 查詢結果 ===");
while (rs.next()) {
dos.writeUTF("用戶ID: " + rs.getString("id"));
dos.writeUTF("用戶名: " + rs.getString("name"));
}
dos.flush();
} catch (Exception e) {
dos.writeUTF("伺服器錯誤: " + e.getMessage());
} finally {
try { if (rs != null) rs.close(); } catch (Exception ignore) {}
try { if (stmt != null) stmt.close(); } catch (Exception ignore) {}
try { if (conn != null) conn.close(); } catch (Exception ignore) {}
}
}
}
<web-app>
<servlet>
<servlet-name>returnMsg</servlet-name>
<servlet-class>returnMsg</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>returnMsg</servlet-name>
<url-pattern>/returnMsg</url-pattern>
</servlet-mapping>
</web-app>
javac -cp ".;%CATALINA_HOME%\common\lib\servlet-api.jar" returnMsg.javareturnMsg.class 放入 %CATALINA_HOME%\webapps\ROOT\WEB-INF\classes\%CATALINA_HOME%\webapps\ROOT\WEB-INF\web.xml 加入上述 servlet 映射。startup.bathttps://localhost:8080/returnMsg (查看網頁原始碼應見查詢結果)。NetMain.java、SendMsgForm.java 放入 src 目錄。| 現象 | 原因 | 解決 |
|---|---|---|
| Tomcat 啟動報 "Unsupported JNI version" | JDK 版本過低 | 升級 JDK 1.4.2+ |
| Servlet 編譯找不到 javax.servlet | classpath 缺 servlet-api.jar | 加入 %CATALINA_HOME%\common\lib\servlet-api.jar |
| MIDlet 連線報 SecurityException | 未簽名 MIDlet 存取網路需用戶授權 | WTK 專案屬性勾選 "Remove leading zeros" 或簽名發布 |
| Access 查詢亂碼 | 字元編碼不匹配 | Servlet 端 dos.writeUTF 已處理 Unicode,MIDlet 端 readUTF 正確還原 |
Connector.openAsync (若支援) 或自行執行緒池管理。本文提供了從零開始建立「J2ME + Servlet + Access」完整聯網應用的最小可行性路徑。掌握此流程後,可輕鬆擴展至企業級行動應用架構。