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

面向 Java 開發者的 Ajax 實戰:構建動態購物車的完整架構解析

     編輯:Java 程式設計入門

Ajax (Asynchronous JavaScript and XML) 讓瀏覽器能在不重新整理頁面的情況下,與伺服器非同步交換資料,構建媲美桌面應用的豐富 Web 體驗。本文以「動態購物車」為例,完整展示從前端 `XMLHttpRequest` 封裝、後端 Servlet 處理、XML 回應序列化、DOM 更新的全鏈路實作。

核心流程:Ajax 往返時序

  1. 使用者點擊「加入購物車」按鈕。
  2. JavaScript 建立 `XMLHttpRequest`,註冊回調,發送 POST 請求至 `cart.do`。
  3. Servlet 接收請求,更新 Session 中購物車狀態,序列化為 XML 回應。
  4. 瀏覽器接收回應,回調函數解析 XML,操作 DOM 更新購物車顯示區域。

前端基礎設施:跨瀏覽器 XMLHttpRequest 工廠

function newXMLHttpRequest() {
    var xmlreq = false;
    if (window.XMLHttpRequest) { // 標準瀏覽器 (IE7+, Firefox, Chrome, Safari)
        xmlreq = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE6 及以下
        try { xmlreq = new ActiveXObject("Msxml2.XMLHTTP"); }
        catch (e1) {
            try { xmlreq = new ActiveXObject("Microsoft.XMLHTTP"); }
            catch (e2) { /* 不支援 */ }
        }
    }
    return xmlreq;
}

購物車互動邏輯:addToCart()

function addToCart(itemCode) {
    var req = newXMLHttpRequest();
    var handler = getReadyStateHandler(req, updateCart); // 回調包裝
    req.onreadystatechange = handler;

    req.open("POST", "cart.do", true); // 非同步
    req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    req.send("action=add&item=" + encodeURIComponent(itemCode));
}

// 通用 readyState 處理器:過濾 readyState===4 並檢查 HTTP 200
function getReadyStateHandler(req, callback) {
    return function() {
        if (req.readyState == 4) {
            if (req.status == 200) callback(req.responseXML);
            else alert("請求失敗: " + req.status);
        }
    };
}

回調處理:updateCart() 解析 XML 並更新 DOM

function updateCart(cartXML) {
    var items = cartXML.getElementsByTagName("item");
    var cartList = document.getElementById("cart-contents");
    var totalEl = document.getElementById("total");

    cartList.innerHTML = ""; // 清空現有列表
    var total = 0.0;

    for (var i = 0; i < items.length; i++) {
        var item = items[i];
        var name = item.getElementsByTagName("name")[0].firstChild.nodeValue;
        var price = parseFloat(item.getElementsByTagName("price")[0].firstChild.nodeValue);
        var qty = parseInt(item.getElementsByTagName("quantity")[0].firstChild.nodeValue);

        var li = document.createElement("li");
        li.appendChild(document.createTextNode(name + " x " + qty + " = $" + (price * qty).toFixed(2)));
        cartList.appendChild(li);
        total += price * qty;
    }
    totalEl.firstChild.nodeValue = "$" + total.toFixed(2);
}

後端 Servlet:CartServlet.doPost()

@WebServlet("/cart.do")
public class CartServlet extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String action = req.getParameter("action");
        String itemCode = req.getParameter("item");

        HttpSession session = req.getSession(true);
        Cart cart = (Cart) session.getAttribute("cart");
        if (cart == null) { cart = new Cart(); session.setAttribute("cart", cart); }

        if ("add".equals(action)) {
            cart.addItem(itemCode); // 業務邏輯封裝在 Cart JavaBean
        }

        // 序列化為 XML
        resp.setContentType("application/xml;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("");
        out.println("");
        for (CartItem ci : cart.getItems()) {
            out.println("  ");
            out.println("    " + escapeXml(ci.getName()) + "");
            out.println("    " + ci.getPrice() + "");
            out.println("    " + ci.getQuantity() + "");
            out.println("  ");
        }
        out.println("");
    }

    private String escapeXml(String s) {
        return s.replace("&", "&").replace("<", "<").replace(">", ">")
                .replace("\"", """).replace("'", "'");
    }
}

Cart JavaBean (Session 狀態封裝)


public class Cart implements Serializable {
    private Map items = new LinkedHashMap<>(); // 保持插入順序

    public void addItem(String itemCode) {
        CartItem ci = items.get(itemCode);
        if (ci == null) {
            // 實際應從資料庫/快取查詢商品詳情
            ci = new CartItem(itemCode, "商品" + itemCode, 19.99);
            items.put(itemCode, ci);
        }
        ci.incrementQuantity();
    }
    public List getItems() { return new ArrayList<>(items.values()); }
}
public class CartItem implements Serializable {
    private String code, name; private double price; private int quantity;
    // 建構子、getter、setter、incrementQuantity()...
}

HTML 頁面片段


<!-- 商品列表 -->
<button onclick="addToCart('hat001')">加入購物車</button>

<!-- 購物車顯示區 (非同步更新) -->
<ul id="cart-contents"></ul>
總價: <span id="total">$0.00</span>

關鍵架構決策與最佳實務

決策點建議理由
資料格式XML (教學) / JSON (實務)JSON 解析更快、體積更小、JS 原生支援
狀態儲存Session 中放 JavaBean物件導向、型別安全、易擴充
同步機制Session 屬性同步 (叢集需 Sticky Session 或 Session 複製)簡單有效,大型系統改用 Redis 分散式 Session
錯誤處理HTTP 狀態碼 + XML/JSON 錯誤碼前端統一攔截顯示友善訊息
安全性CSRF Token、XSS 防護 (escapeXml)、HTTPS防範跨站偽造請求與腳本注入

漸進增強與無障礙考量

  • **無 JavaScript 降級:** 表單保留傳統 `action="cart.do" method="POST"` 提交,頁面重新整理顯示結果。
  • **ARIA 標記:** `aria-live="polite"` 標示動態更新區域,螢幕閱讀器可感知變化。
  • **鍵盤可達:** 按鈕、連結可透過 Tab 聚焦,Enter/Space 觸發。

Ajax 讓 Java Web 應用脫離「請求-回應-整頁重繪」的傳統模式,邁向單頁應用 (SPA) 時代的先鋒技術。掌握其核心機制,是通往現代前後端分離架構的必經之路。

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