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

JavaWeb JSP Session 購物車修改商品數量:前端 JS 獲取輸入值提交後台更新 Session 完整流程

     編輯:程式設計疑難解答

核心業務流程

用戶在購物車頁面修改輸入框數量
      ↓
前端 JS 監聽 change/blur 事件,獲取 (商品ID, 新數量)
      ↓
AJAX (fetch/axios/jQuery) 異步提交到後台 Servlet/Controller
      ↓
後台從 Session 獲取購物車 List/Map,更新對應商品數量
      ↓
後台返回 JSON 結果 {success: true, newTotal: 99.00}
      ↓
前端 JS 更新頁面顯示 (小計、總價),無需刷新整頁

前端實現 (原生 Fetch API 示例)

<!-- 購物車列表項模板 -->
<c:forEach items="${cartItems}" var="item">
    <tr data-id="${item.productId}">
        <td>${item.name}</td>
        <td>¥${item.price}</td>
        <td>
            <input type="number" class="qty-input" value="${item.quantity}" min="1" max="99" 
                   data-id="${item.productId}" style="width: 60px;" />
        </td>
        <td class="subtotal">¥${item.price * item.quantity}</td>
    </tr>
</c:forEach>

<script>
document.querySelectorAll('.qty-input').forEach(input => {
    input.addEventListener('change', function() {
        const productId = this.dataset.id;
        const newQty = parseInt(this.value, 10);
        if (isNaN(newQty) || newQty < 1) {
            alert('請輸入有效數量');
            this.value = this.defaultValue; // 恢復原值
            return;
        }
        updateQuantity(productId, newQty, this);
    });
});

async function updateQuantity(productId, quantity, inputEl) {
    try {
        const response = await fetch('/CartServlet', {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            body: `action=update&productId=${productId}&quantity=${quantity}`
        });
        const result = await response.json();
        if (result.success) {
            // 更新小計
            const row = inputEl.closest('tr');
            const price = parseFloat(row.querySelector('td:nth-child(2)').textContent.replace('¥',''));
            row.querySelector('.subtotal').textContent = '¥' + (price * quantity).toFixed(2);
            // 更新總價 (假設後台返回)
            document.getElementById('totalPrice').textContent = '¥' + result.newTotal.toFixed(2);
        } else {
            alert('更新失敗: ' + result.msg);
            inputEl.value = inputEl.defaultValue;
        }
    } catch (e) {
        console.error(e);
        alert('網絡錯誤');
        inputEl.value = inputEl.defaultValue;
    }
}
</script>

後台 Servlet 實現

@WebServlet("/CartServlet")
public class CartServlet extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        
        String action = req.getParameter("action");
        if ("update".equals(action)) {
            String productId = req.getParameter("productId");
            int quantity = Integer.parseInt(req.getParameter("quantity"));
            
            HttpSession session = req.getSession();
            // 假設購物車存為 Map key=productId
            @SuppressWarnings("unchecked")
            Map cart = (Map) session.getAttribute("cart");
            
            if (cart != null && cart.containsKey(productId)) {
                CartItem item = cart.get(productId);
                if (quantity > 0) {
                    item.setQuantity(quantity);
                } else {
                    cart.remove(productId); // 數量 <=0 視為刪除
                }
                // 重新計算總價
                double total = cart.values().stream()
                                   .mapToDouble(i -> i.getPrice() * i.getQuantity())
                                   .sum();
                out.write("{\"success\":true,\"newTotal\":" + total + "}");
            } else {
                out.write("{\"success\":false,\"msg\":\"商品不存在\"}");
            }
        } else {
            out.write("{\"success\":false,\"msg\":\"未知操作\"}");
        }
        out.flush();
    }
}

CartItem 實體類

public class CartItem implements Serializable {
    private String productId;
    private String name;
    private double price;
    private int quantity;
    // Getter/Setter/構造函數...
}

關鍵點總結

  1. Session 存儲結構:推薦 `Map` (Key=ProductId),O(1) 查找更新;或 `List` 需遍歷。
  2. 前端驗證:輸入框 `type="number" min="1"` + JS 邏輯雙重保障。
  3. AJAX 異步體驗:無刷新更新,返回新總價由前端渲染,減輕服務端壓力。
  4. 併發安全:單用戶 Session 通常單線程訪問,無需加鎖;若極端並發可用 `ConcurrentHashMap` 或 `synchronized(session)`。
  5. 數據持久化:生產環境購物車應寫入 Redis/數據庫,Session 僅作緩存,防止 Session 失效丟失數據。

總結

「前端 JS 獲取輸入值 → AJAX 提交 → 後台更新 Session Map → 返回 JSON → 前端局部刷新」是現代 JavaWeb 購物車修改數量的標準模式。核心在於**前後端職責分離**:後台只管數據邏輯,前台只管交互渲染。

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