购物车原理以及实现

购物车原理以及实现

本文讲什么

可以看到,购物车这样一个功能模块,在各种购物类APP或者web应用中绝对是必不可少的东西.不论在大学中的课程设计,还是在实际的项目开发中,绝对非常重要且有些复杂的内容. 在实际操作中,身边有很多的小伙伴遇到编写购物车的代码的时候,有时候真的是一脸懵逼,总是搞不明白设计的思路,这就是本文写作的原因. 所以,本文适合搞不清楚购物车实现原理,知道原理但是实际编码不知道如何下手的小伙伴,我将给出一个思路以及实际的代码供大家参考. 在本文中,我将会用尽可能简单的句子,表达出我想表达的意思.废话不多说,开始我们的购物车实战!

购物车的几种实现方式

购物车的实现方式有很多,但是最常见的就三种:Cookie,Session,数据库.三种方法各有优劣,适合的场景各不相同.

Cookie方法:通过把购物车中的商品数据写入Cookie中,再通过浏览器进行读取.这个方法,适合在用户没有登录的情况下使用,但是有个非常严重的缺点,即在用户禁用了Cookie的时候是无法使用的.Session方法:通过Session来保存商品信息,这确实是个好的方法,适合用户已经登录的情况,将数据放在Session中,用户就能读取购物车中的商品信息,而且速度十分的快.但是缺点也很明显,由于Session是建立在用户客户端和服务器之间的,在Session中保存数据,无疑会增加服务器的负担.数据库(Redis):数据库无疑是一种非常棒的保存购物车中信息的有效途径,且能够持久化保存,但是问题也很明显,那就是读取速度会差强人意.

好了,下面来说一下几种实现方式的应用场景.

当用户没有登录的情况下,用户将商品加入购物车,此时的商品信息是写入了Cookie中,并且会设置一个保存时间,即使关闭浏览器过一段时间访问仍能看到购物车中的信息.(或者将购物数据写入Session中,但是关闭浏览器,购物车中的信息也就不见了)用户登陆后,如果在Session中存储了商品信息且没有关闭浏览器(如果在Cookie中存储了商品信息且没有过期),将会读取其中的商品信息,并且将这些信息写入数据库中进行持久保存.

本文的行文方式说明

经过上面的讲解,我想你一定对购物车有所了解,为了使读者更加清晰的明白购物车的实现,我们省去了在未结算的状态下的持久化数据库. 也就是说,在文章中,我将使用Session来实现购物车,并且当用户没有登录的情况下,禁止用户将商品加入购物车.当然你不必为此担忧,即使我这样做,我的代码已经包括了整个购物操作的绝大多数步骤.请耐心向下看. 此外,本文使用SSM框架作为行文代码. 如果你是初学者也不必担心,我将为你提供一套项目的源代码,可以在我的GitHub中获取:餐厅点餐系统,这套系统是基于servlet+jsp+mysql开发的,注释非常完善,当然最重要的模块也就是下单模块肯定是有的,而且非常完善,欢迎下载.

购物车模块的实现

数据库设计

用户表

字段意义id用户iduserName用户名password用户密码

商品表

字段意义id商品idcommName商品名称price商品价格

订单表

字段意义id订单idcommName商品名称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 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 eqUser = userMapper.selectByExample(example);

//如果没有查询到user,则返回false

if (eqUser == null){

return false;

}

return eqUser.get(0).getPassword().equals(user.getPassword());

}

}

确认用户登录以后,需要把用户信息放在session中以便后续过程使用.

###用户购物模块 当用户登录以后,展示在用户眼前的界面是这样的(页面模板来自菜鸟教程,经过改编):

左栏中的数据来自登录代码中的

List 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 = $("").append("#");

var commnameTd = $("").append(item.commname);

var countTd = $("").append(item.count);

var subtotalTd = $("").append(item.subtotal);

$("")

.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 shopcart = (List) 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 joinCart(String id, HttpSession session, Model model) {

//标识符:判断是否存在此商品

boolean flag = false;

//通过id查询商品信息

Common common = shopService.selectCommById(Integer.parseInt(id));

//从session中获取购物车信息

List shopcart = (List) 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中保存的数据取出,然后遍历将数据写入数据库,进行持久化的操作即可. 以上. 获取文中项目代码:https://download.csdn.net/download/yanmiao0715/10570386 如果您的积分不够,欢迎关注我的微信公众号:最高权限比特流,回复"购物车源代码"进行下载.

结语

感谢您的阅读,如果您对文章有任何问题,欢迎留言,欢迎联系我:roobtyan@outlook.com. 也欢迎您关注我的微信公众号:最高权限比特流. 以及我的个人博客:www.roobtyan.cn

相关推荐

11位明星豪宅大盘点:赵丽颖1.4亿进不了前三,榜首实至名归
创业初期,要先学会自己赚钱
365sport365

创业初期,要先学会自己赚钱

📅 06-29 👁️ 9545
小米手机如何激活 小米激活教程
beat365官网备用

小米手机如何激活 小米激活教程

📅 06-28 👁️ 3178