購物車原理以及實現

Roobtyan發表於2018-08-19

本文講什麼

可以看到,購物車這樣一個功能模組,在各種購物類APP或者web應用中絕對是必不可少的東西.不論在大學中的課程設計,還是在實際的專案開發中,絕對非常重要且有些複雜的內容. 在實際操作中,身邊有很多的小夥伴遇到編寫購物車的程式碼的時候,有時候真的是一臉懵逼,總是搞不明白設計的思路,這就是本文寫作的原因. 所以,本文適合搞不清楚購物車實現原理,知道原理但是實際編碼不知道如何下手的小夥伴,我將給出一個思路以及實際的程式碼供大家參考. 在本文中,我將會用盡可能簡單的句子,表達出我想表達的意思.廢話不多說,開始我們的購物車實戰!

購物車的幾種實現方式

購物車的實現方式有很多,但是最常見的就三種:Cookie,Session,資料庫.三種方法各有優劣,適合的場景各不相同.

  • Cookie方法:通過把購物車中的商品資料寫入Cookie中,再通過瀏覽器進行讀取.這個方法,適合在使用者沒有登入的情況下使用,但是有個非常嚴重的缺點,即在使用者禁用了Cookie的時候是無法使用的.
  • Session方法:通過Session來儲存商品資訊,這確實是個好的方法,適合使用者已經登入的情況,將資料放在Session中,使用者就能讀取購物車中的商品資訊,而且速度十分的快.但是缺點也很明顯,由於Session是建立在使用者客戶端和伺服器之間的,在Session中儲存資料,無疑會增加伺服器的負擔.
  • 資料庫(Redis):資料庫無疑是一種非常棒的儲存購物車中資訊的有效途徑,且能夠持久化儲存,但是問題也很明顯,那就是讀取速度會差強人意.

好了,下面來說一下幾種實現方式的應用場景.

  • 當使用者沒有登入的情況下,使用者將商品加入購物車,此時的商品資訊是寫入了Cookie中,並且會設定一個儲存時間,即使關閉瀏覽器過一段時間訪問仍能看到購物車中的資訊.(或者將購物資料寫入Session中,但是關閉瀏覽器,購物車中的資訊也就不見了)
  • 使用者登陸後,如果在Session中儲存了商品資訊且沒有關閉瀏覽器(如果在Cookie中儲存了商品資訊且沒有過期),將會讀取其中的商品資訊,並且將這些資訊寫入資料庫中進行持久儲存.

本文的行文方式說明

經過上面的講解,我想你一定對購物車有所瞭解,為了使讀者更加清晰的明白購物車的實現,我們省去了在未結算的狀態下的持久化資料庫. 也就是說,在文章中,我將使用Session來實現購物車,並且當使用者沒有登入的情況下,禁止使用者將商品加入購物車.當然你不必為此擔憂,即使我這樣做,我的程式碼已經包括了整個購物操作的絕大多數步驟.請耐心向下看. 此外,本文使用SSM框架作為行文程式碼. 如果你是初學者也不必擔心,我將為你提供一套專案的原始碼,可以在我的GitHub中獲取---->餐廳點餐系統,這套系統是基於servlet+jsp+mysql開發的,註釋非常完善,當然最重要的模組也就是下單模組肯定是有的,而且非常完善,歡迎下載.

購物車模組的實現

資料庫設計

  • 使用者表 | 欄位 | 意義 | |--------|--------| |id|使用者id| |userName|使用者名稱| |password|使用者密碼|

  • 商品表 | 欄位 | 意義 | |--------|--------| |id|商品id| |commName|商品名稱| |price|商品價格|

  • 訂單表 | 欄位 | 意義 | |--------|--------| |id| 訂單id| |commName|商品名稱| |count|商品數量| |subtotal|商品小計| |total|總價|

使用者登入

為了實現我上述的思路,肯定是要求使用者先行登入.程式碼如下.

  • LoginController
@Controller
public class LoginController {
    private LoginService loginService;
    private CommonService commonService;

    @Autowired
    public LoginController(LoginService loginService, CommonService commonService) {
        this.loginService = loginService;
        this.commonService = commonService;
    }

    @RequestMapping("/login")
    public String login(User user, HttpSession session, Model model) {
        //登入驗證
        if (loginService.isUser(user)) {
            List<Common> commons = commonService.selectAllCommons();
            model.addAttribute("commons", commons);
            model.addAttribute("username", user.getUsername());
            //把使用者資訊儲存到session中
            session.setAttribute("user", user);
            return "shopping";
        } else {
            model.addAttribute("message", "使用者名稱或密碼錯誤");
            return "index";
        }
    }
}

複製程式碼

這是最常規的使用者登入的程式碼,思路就是拿著使用者名稱到資料庫裡面查詢,如果能查到,則說明使用者名稱無誤,如果查不到則說明沒有此使用者,提示使用者註冊.如果使用者名稱存在,再比對密碼,一般密碼不會像我們這樣直接在資料庫裡面使用明文密碼,都是會加鹽的(MD5演算法).如果比對密碼的結果為true,則使用者可以登入.比對過程isUser的程式碼如下.

@Service
public class LoginService {
    private UserMapper userMapper;

    @Autowired
    public LoginService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 判斷使用者名稱或密碼是否正確
     * @param user
     * @return
     */
    public boolean isUser(User user){
        UserExample example = new UserExample();
        UserExample.Criteria criteria  = example.createCriteria();
        criteria.andUsernameEqualTo(user.getUsername());
        List<User> eqUser = userMapper.selectByExample(example);
        //如果沒有查詢到user,則返回false
        if (eqUser == null){
            return false;
        }
        return eqUser.get(0).getPassword().equals(user.getPassword());
    }

}
複製程式碼

確認使用者登入以後,需要把使用者資訊放在session中以便後續過程使用.

###使用者購物模組 當使用者登入以後,展示在使用者眼前的介面是這樣的(頁面模板來自菜鳥教程,經過改編):

購物車原理以及實現

左欄中的資料來自登入程式碼中的

List<Common> commons = commonService.selectAllCommons();
model.addAttribute("commons", commons);
複製程式碼

當點選加入購物車以後,觸發onlick事件:onclick="javascript:joinCart(${common.id})" 詳細程式碼如下:

function joinCart(id) {
        $.ajax({
            url: "${pageContext.request.contextPath}/shop/joinCart",
            data: "id=" + id,
            type: "POST",
            success: function (result) {
                alert("加入購物車成功!");
                //清空購物車列表
                $("#shop_cart tbody").empty();
                //動態構建購物車列表
                var obj = result;
                $.each(obj,function (index,item) {
                   var emptyTd = $("<td></td>").append("#");
                   var commnameTd = $("<td></td>").append(item.commname);
                   var countTd = $("<td></td>").append(item.count);
                   var subtotalTd = $("<td></td>").append(item.subtotal);

                   $("<tr></tr>")
                       .append(emptyTd)
                       .append(commnameTd)
                       .append(countTd)
                       .append(subtotalTd)
                       .appendTo("#shop_cart tbody");
                   //設定總金額
                   var totalSpan = document.getElementById("subtotal");
                   totalSpan.innerHTML = item.total;
                });


            }
        })
    }
複製程式碼

可以看到,當觸發這個方法時,實際上是使用了非同步請求的方式向服務端傳送資料,服務端做相應處理以後,封裝購物車列表,然後把購物車商品列表以JSON格式傳回,也就是封裝在result中,利用js,動態構建購物車列表.於是就出現下面這種情況. 當將商品加入購物車以後:

購物車原理以及實現

首先提示使用者已經加入購物車,然後在利用非同步請求構建整個購物車,如果你對前端的瞭解並不是很深,不必擔心,這部分內容實際上很簡單,你可以隨便百度一下這個知識點,記住就好了.實際上就是利用js操作json資料而已.

購物車原理以及實現

其實對於初學者來說,感覺上面的過程挺神奇的,其實不然.前端的程式碼看完了,我就來給你詳細的解釋一下後端的程式碼. 首先,可以將後段程式碼分成兩部分,一部分是判斷,各種判斷,另外一部分是封裝資料,相對簡單.

 //識別符號:判斷是否存在此商品
boolean flag = false;
//通過id查詢商品資訊
Common common = shopService.selectCommById(Integer.parseInt(id));
//從session中獲取購物車資訊
List<Order> shopcart = (List<Order>) session.getAttribute("shopcart");
//獲取使用者資訊
User user = (User) session.getAttribute("user");
if (user == null) {
    //如果使用者為空,則直接返回,讓使用者登入
    throw new RuntimeException("使用者未登入");
}
//判斷購物車列表是否為空
if (shopcart == null) {
    //new 一個集合
    shopcart = new ArrayList<>();
}
複製程式碼

先判斷使用者是否已經登入,如果使用者已經登入,則執行後續流程,如果使用者沒有登入,則直接丟擲異常,交給非同步請求的error處理,提示使用者登入即可. 如果使用者已經登入,則繼續下面的步驟,判斷購物車是否為空,為空也就是說明使用者沒有將任何商品加入購物車,則需要建立一個新的ArrayList集合,同時利用商品id查詢出的商品資訊,封裝訂單物件.

else {
    for (Order order : shopcart) {
        //判斷是否存在此商品,存在則數量+1
        if (order.getCommname().equals(common.getCommname())) {
            flag = true;
            order.setCount(order.getCount() + 1);
            order.setSubtotal(order.getCount() * common.getPrice());
        }
    }
}
複製程式碼

在遍歷的過程中,如果遍歷的資料的commName和查到的name相同的話,則證明是同一件商品,則將此商品的數量+1,然後再設定小計價格即可.同時將flag設定為true,表示遍歷到了同樣的資料. 如果沒有遍歷到名稱相同的商品,則直接新建一個物件,封裝資料,加入集合.

//如果購物車中沒有當前商品的資訊,則新增商品
if (!flag) {
    Order order = new Order();
    order.setCommname(common.getCommname());
    order.setCount(1);
    order.setSubtotal(common.getPrice());
    //把商品加入集合
    shopcart.add(order);
}
複製程式碼

最後一步就是計算總價格,封裝資料即可.

//計算總價格
Double total = 0d;
for (Order order : shopcart) {
    total += order.getSubtotal();
}
for (Order order : shopcart) {
    order.setTotal(total);
}
//設定session
session.setAttribute("shopcart", shopcart);
//返回list
return shopcart;
複製程式碼

購物車全部程式碼如下:

Controller
@RequestMapping("/shop")
public class ShopController {
    private ShopService shopService;

    public ShopController(ShopService shopService) {
        this.shopService = shopService;
    }

    @RequestMapping("/joinCart")
    @ResponseBody
    public List<Order> joinCart(String id, HttpSession session, Model model) {
        //識別符號:判斷是否存在此商品
        boolean flag = false;
        //通過id查詢商品資訊
        Common common = shopService.selectCommById(Integer.parseInt(id));
        //從session中獲取購物車資訊
        List<Order> shopcart = (List<Order>) session.getAttribute("shopcart");
        //獲取使用者資訊
        User user = (User) session.getAttribute("user");
        if (user == null) {
            //如果使用者為空,則直接返回,讓使用者登入
            throw new RuntimeException("使用者未登入");
        }
        //判斷購物車列表是否為空
        if (shopcart == null) {
            //new 一個集合
            shopcart = new ArrayList<>();
        } else {
            for (Order order : shopcart) {
                //判斷是否存在此商品,存在則數量+1
                if (order.getCommname().equals(common.getCommname())) {
                    flag = true;
                    order.setCount(order.getCount() + 1);
                    order.setSubtotal(order.getCount() * common.getPrice());
                }
            }
        }
        //如果購物車中沒有當前商品的資訊,則新增商品
        if (!flag) {
            Order order = new Order();
            order.setCommname(common.getCommname());
            order.setCount(1);
            order.setSubtotal(common.getPrice());
            //把商品加入集合
            shopcart.add(order);
        }
        //計算總價格
        Double total = 0d;
        for (Order order : shopcart) {
            total += order.getSubtotal();
        }
        for (Order order : shopcart) {
            order.setTotal(total);
        }
        //設定session
        session.setAttribute("shopcart", shopcart);
        //返回list
        return shopcart;
    }

}
複製程式碼

關於操作購物車商品數量及結算

首先說操作購物車商品數量,既然我們能夠按照通過id加商品的數量,肯定也是能夠按照商品id減商品的數量,這部分無需多說,相信按照上面的程式碼,以你的聰明才智,肯定是能夠做出來的. 至於結算操作,就更加單了. 使用者點選結算按鈕以後,跳轉到後臺,通過後臺程式碼,先把session中儲存的資料取出,然後遍歷將資料寫入資料庫,進行持久化的操作即可. 以上. 獲取文中專案程式碼:download.csdn.net/download/ya… 如果您的積分不夠,歡迎關注我的微信公眾號:最高許可權位元流,回覆"購物車原始碼"進行下載.

結語

感謝您的閱讀,如果您對文章有任何問題,歡迎留言,歡迎聯絡我:roobtyan@outlook.com. 也歡迎您關注我的微信公眾號:最高許可權位元流. 以及我的個人部落格:www.roobtyan.cn

相關文章