购物车的原理以及实现

  今天模拟京东的购物车实现原理完成了购物车模块的开发, 给大家分享下。

京东的购物车实现原理:在用户登录和不登录的状态下对购物车存入cookie还是持久化到redis中的实现。下面就来具体说次购物车的实现过程

两种情况:

用户登录,购物车存入redis中

用户未登录,购物车存入cookie中

比较两种方式的优缺点:

 cookie:优点:数据保存在用户浏览器中,不占用服务端内存;用户体检效果好;代码实现简单

     缺点:cookie的存储空间只有4k;更换设备时,购物车信息不能同步;cookie禁用,不提供保存

 redis:优点:数据能够持久化;实现了购物车同步

     缺点:增加了数据库的压力,速度慢

先介绍使用cookie存储购物车的实现思路

1、用户未登录状态下,用户添加购物车,首先从cookie中查询购物车中的商品列表

2、 判断cookie的商品列表中是否有要添加的商品信息

3、如果cookie中有该商品信息,将商品的数量相加

4、如果没有,根据商品的id值查询商品信息

5、将商品添加到购物车列表中

6、将购物车列表写入cookie中,设置cookie的过期时间

7、将cookie返回给客户端。

购物车的实现:

这里直接使用商品作为购物项对象,在页面中计算购物项的小计和购物车的总金额

package nyist.e3.pojo;

import java.io.Serializable;
import java.util.Date;

public class TbItem implements Serializable{
    private Long id;

    private String title;

    private String sellPoint;

    private Long price;

    private Integer num;//作为购物项购买的商品数量

    private String barcode;

    private String image;//展示购物项中的图片

    private Long cid;

    private Byte status;

    private Date created;

    private Date updated;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title == null ? null : title.trim();
    }

    public String getSellPoint() {
        return sellPoint;
    }

    public void setSellPoint(String sellPoint) {
        this.sellPoint = sellPoint == null ? null : sellPoint.trim();
    }

    public Long getPrice() {
        return price;
    }

    public void setPrice(Long price) {
        this.price = price;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

    public String getBarcode() {
        return barcode;
    }

    public void setBarcode(String barcode) {
        this.barcode = barcode == null ? null : barcode.trim();
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image == null ? null : image.trim();
    }

    public Long getCid() {
        return cid;
    }

    public void setCid(Long cid) {
        this.cid = cid;
    }

    public Byte getStatus() {
        return status;
    }

    public void setStatus(Byte status) {
        this.status = status;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }
}

cookie中实现添加购物车的代码:

@Controller
public class ShopCartController {

    @Autowired
    private TbItemService tbItemService;

    @Autowired
    private ShopCartService shopCartService;
    // 获取过期时间
    @Value("${EXPIRE_KEY}")
    private Integer EXPIRE_KEY;

    @Value("${CART_COOKIE}")
    private String CART_COOKIE;

    /**
     * 需求:将商品加入购物车中未登录状态下,将购物超过添加到cookie中
     *
     * 分析:1、从cookie中获取购物车信息
     * 2、判断购物车中的商品,如果添加的商品存在,数量相加,不存在,根据商品id查询商品信息,添加到cookie中
     * 3、将购物车列表信息写入cookie中
     *
     *
     * @param itemId
     * @param num
     * @return
     */
    @RequestMapping("/cart/add/{itemId}")
    public String addCart(@PathVariable Long itemId, @RequestParam(defaultValue = "1") Integer num,
            HttpServletRequest request, HttpServletResponse response) {
     // 1.获得购物车列表
        List<TbItem> itemList = getCartItemList(request);
        // 用来判断商品是否存在的标志
        boolean flag = false;
        // 2、循环遍列表中的商品信息
        for (TbItem tbItem : itemList) {
            // 3、判断添加的商品是否存在
            if (tbItem.getId() == itemId.longValue()) {
                // 4、添加的商品在cookie中存在,将数量相加
                tbItem.setNum(tbItem.getNum() + num);
                // 重置标签
                flag = true;
                // 跳出循环
                break;
            }
        }
        if (!flag) {
            // cookie中没有添加的商品信息
            // 通过商品id查询商品信息
            TbItem item = tbItemService.getItemById(itemId);
            item.setNum(num);
            if (StringUtils.isNotBlank(item.getImage())) {
                // 取一张图片用于展示使用
                item.setImage(item.getImage().split(",")[0]);
            }
            // 将商品添加购物车
            itemList.add(item);
        }
        //将购物车写入cookie中

        CookieUtils.setCookie(request, response, CART_COOKIE, JsonUtils.objectToJson(itemList),EXPIRE_KEY,true);

        return "cartSuccess";

    }

}

cookie中查询购物车列表:

思路:

1、根据cookie的name值直接取出商品列表信息

2、将购物车列表添加到model中,返回逻辑视图

private List<TbItem> getCartItemList(HttpServletRequest request) {
        // 使用utf-8,需要设置第三个参数为true
        String json = CookieUtils.getCookieValue(request, CART_COOKIE, true);
        if (StringUtils.isNotBlank(json)) {
            // 返回cookie中取出的数据集合
            return JsonUtils.jsonToList(json, TbItem.class);
        }
        // 返回空集合对象
        return new ArrayList<>();
    }

@RequestMapping("/cart/cart")
    public String getCartList(HttpServletRequest request, HttpServletResponse response, Model model) {
        // 从cookie中取出商品信息,
        List<TbItem> itemList = getCartItemList(request);
        // 将购物车信息返回给页面中
        model.addAttribute("cartList", itemList);
        // 跳转逻辑视图
        return "cart";
    }

cookie中实现删除购物车中商品的功能:

1、接收页面传递的善品id值

2、从cookie中取出购物车列表,进行循环遍历,然后遍历的每一个商品信息和要删除的商品进行对比

3、如果存在就从购物车列表中将该商品移除

4、重新将购物车列表写入cookie中

5、将cookie信息响应给客户端

@RequestMapping("/cart/delete/{itemId}")
    public String deleteCartItem(@PathVariable Long itemId, HttpServletRequest request, HttpServletResponse response) {
        List<TbItem> list = getCartItemList(request);
        for (TbItem tbItem : list) {
            if (tbItem.getId() == itemId.longValue()) {
                list.remove(tbItem);
                break;
            }
        }
        // 删除成功后,将购物车列表写入cookie中
        CookieUtils.setCookie(request, response, CART_COOKIE, JsonUtils.objectToJson(list), EXPIRE_KEY, true);

        // 删除成功后,重定向到购物车列表页面
        return "redirect:/cart/cart.html";

    }

cookie购物车的添加,查询,删除已经实现实现,更改方法和删除方法实现过程基本一样

登录状态下redis购物车的实现

实现redis购物车添加功能

思路:

1、从request域中取出登录用户的信息

2、使用redis存储购物车列表 使用redis中的hash数据类型  hash的key 使用登录用户id值,field的key使用商品的id值,将商品的信息作为field的value值

3、完成cookie存储购物车列表的功能

实现的代码:

@Override
    public E3Result addCart(Long userId, Long itemId, Integer num) {
        try {
            // 从redis中取出购物车,判断是否已经有购物项
            Boolean hexists = jedisClient.hexists(CART_REDIS_KEY_PRE + ":" + userId + "", itemId + "");
            if (hexists) {
                // 表示购物车中已经有该商品,只需要将该商品的数量相加即可
                String hget = jedisClient.hget(CART_REDIS_KEY_PRE + ":" + userId + "", itemId + "");
                // 将数量相加
                TbItem item = JsonUtils.jsonToPojo(hget, TbItem.class);
                item.setNum(item.getNum() + num);
                // 将商品重新放入购物车中
                jedisClient.hset(CART_REDIS_KEY_PRE + ":" + userId + "", itemId + "", JsonUtils.objectToJson(item));
                return E3Result.ok();
            }

            // 表示购物车中没有要添加的商品信息
            // 根据商品的id查询商品的信息
            TbItem item = itemMapper.selectByPrimaryKey(itemId);
            item.setNum(num);
            if (StringUtils.isNotBlank(item.getImage())) {
                item.setImage(item.getImage().split(",")[0]);
            }
            // 将商品信息存入购物车中
            jedisClient.hset(CART_REDIS_KEY_PRE + ":" + userId + "", itemId + "", JsonUtils.objectToJson(item));
            return E3Result.ok();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return E3Result.build(400, "商品添加购物车失败");

    }

展示登录状态下的购物车列表:需要将cookie中的购物车和redis中的购物车整合

1、从cookie中取出购物车列表对象

2、从redis中取出购物车对象

3、将cookie中的购物车列表和redis中的购物车列表整合(取出cookie中的购物车列表,然后添加到redis购物车中即可)

5、最终展示的结果以redis中的购物车为主

/**
     * cookie中的购物车和redis中的购物车进行整合
     */
    @Override
    public E3Result mergeCart(Long userId, List<TbItem> itemList) {
        for (TbItem tbItem : itemList) {
            // 只需要调用登录状态下添加购物车业务处理逻辑即可
            addCart(userId, tbItem.getId(), tbItem.getNum());
        }
        return E3Result.ok();
    }

redis购物车中删除购物项

将用户的id值和商品的id值分别作为hahs的key和field的key,调用redis中的hdel(String key,String...field)即可完成删除功能

/**
     * 删除购物车
     *
     * @return
     *
     */
    @Override
    public E3Result deleteCartItem(Long id, Long itemId) {
        Long hdel = jedisClient.hdel(CART_REDIS_KEY_PRE + ":" + id + "", itemId + "");
        System.out.println("删除购物车购物项为"+hdel);
        return E3Result.ok();
    }

redis购物车中更新购买商品的数量

    /**
     * 更新购物车中商品的数量
     */
    @Override
    public E3Result updateRedisNum(Long id, Long itemId, Integer num) {
        // 取出需要更改数量的商品信息
        String hget = jedisClient.hget(CART_REDIS_KEY_PRE + ":" + id + "", itemId + "");
        // 将取出的json数据转换为商品对象,然后更新数量
        TbItem item = JsonUtils.jsonToPojo(hget, TbItem.class);
        item.setNum(num);
        // 更新成功后,将数据写到redis购物车中
        jedisClient.hset(CART_REDIS_KEY_PRE + ":" + id + "", itemId + "", JsonUtils.objectToJson(item));
        return E3Result.ok();
    }

当用户点击去结算时:跳转到订单确认页面

1、生成订单详情

2、配送地址信息

3、选择支付方式

在确认订单之前, 应该判断用户是否是登录装态,可以使用拦截器实现

1、自定义拦截器实现HandlerInteceptor接口

2、从cookie中去token消息(登录认证的令牌)

3、判断token的值是否为空,如果为空,就跳转到用户登录页面完成登录,同时需要将当前地址栏的url作为参数传递(在登录的业务逻辑中,接收该url,完成登录后,跳转会该页面)

4、如果token不为空,根据token查询用户信息,然后将用户信息写入request域中,拦截器执行放行操作

5、此时获取到的购物车列表是从redis中读出的和cookie整合的最新的购物车。

拦截器的实现过程:

public class LoginInterceptor implements HandlerInterceptor {

    @Value("${TT_TOKEN}")
    private String TT_TOKEN;
    @Value("${SSO_LOGIN_URL}")
    private String SSO_LOGIN_URL;

    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //执行Handler之前执行此方法
        // a)从cookie中取token。
        String token = CookieUtils.getCookieValue(request, TT_TOKEN);
        if (StringUtils.isBlank(token)) {
            //取当前请求的url
            String url = request.getRequestURL().toString();
            // b)没有token,需要跳转到登录页面。
            response.sendRedirect(SSO_LOGIN_URL + "?redirectUrl=" + url);
            //拦截
            return false;
        }
        // c)有token。调用sso系统的服务,根据token查询用户信息。
        e3Result result = userService.getUserByToken(token);
        if (result.getStatus() != 200) {
            // d)如果查不到用户信息。用户登录已经过期。需要跳转到登录页面。
            //取当前请求的url
            String url = request.getRequestURL().toString();
            // b)没有token,需要跳转到登录页面。
            response.sendRedirect(SSO_LOGIN_URL + "?redirectUrl=" + url);
            //拦截
            return false;
        }
        // e)查询到用户信息。放行。
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // 执行Handler之后返回ModelAndView之前

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // 返回ModelAndView之后,执行。异常处理。

    }

}
@Override
    public E3Result getToken(String token) {
        try {
            // 从redis中取值
            String json = jedisClient.get("USER_INFO:" + token);
            if (StringUtils.isBlank(json)) {
                // json为空,表示已经过期
                return E3Result.build(400, "session已经过期,请重新登录");
            }
            //将json对象转化为pojo对象
            TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
            //重新设置用户登录信息的过期时间
            jedisClient.expire("USER_INFO:" + token, 1800);
            //将获取的user信息使用E3Result包装后返回
            return E3Result.ok(user);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

拦截器定义好之后,需要在springmvc中配置

<mvc:interceptors>
        <mvc:interceptor>
            <!-- 拦截所有请求 -->
            <mvc:mapping path="/**" />
            <!-- 注册自定义拦截器 -->
            <bean class="nyist.e3.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

在登录页面接收url,实现sso系统的回调 接收的redirectUrl即为拦截中请求登录页面传递的参数

至此:购物车模块的功能基本实现,错误的地方希望大家多多指正。

原文地址:https://www.cnblogs.com/shuai-server/p/8996625.html

时间: 2024-10-09 07:41:28

购物车的原理以及实现的相关文章

[项目构建 十一]babasport 购物车的原理及实现.

今天来开始写一下关于购物车的东西, 这里首先抛出四个问题: 1)用户没登陆用户名和密码,添加商品, 关闭浏览器再打开后 不登录用户名和密码 问:购物车商品还在吗? 2)用户登陆了用户名密码,添加商品,关闭浏览器再打开后 不登录用户名和密码 问:购物车商品还在吗? 3)用户登陆了用户名密码,添加商品, 关闭浏览器,然后再打开,登陆用户名和密码  问:购物车商品还在吗? 4)用户登陆了用户名密码,添加商品, 关闭浏览器 外地老家打开浏览器  登陆用户名和密码 问:购物车商品还在吗? 上面四个问题都是

购物车实现原理

购物车的实现原理 购物车相当于现实中超市的购物车,不同的是一个是实体车,一个是虚拟车而已.用户可以在购物网站的不同页面之间跳转,以选购自己喜爱的商品,点击购买时,该商品就自动保存到你的购物车中,重复选购后,最后将选中的所有商品放在购物车中统一到付款台结账,这也是尽量让客户体验到现实生活中购物的感觉.服务器通过追踪每个用户的行动,以保证在结账时每件商品都物有其主. 购物车的功能包括以下几项: n         把商品添加到购物车,即订购 n         删除购物车中已定购的商品 n     

购物车原理

购物车的原理就是点击加入购物车之后,将商品的一些 信息储存在localStorage:然后在购物车界面获取到 localStorage然后取出他们的值,然后放在页面上展示即可: 其实很简单的,接下来就是 代码展示: $scope.commit=function (a,a1,b,c,d,e) { $scope.isShow2=false; if(!window.localStorage){ alert("浏览器支持localstorage"); return false; }else{

[项目构建 十二]babasport 订单的处理原理及代码实现.

上一篇博文我们已经介绍了购物车的原理及实现, 那么购物车再往后就是提交订单了, 订单的实现方式是怎么样的呢? 那么下面就让我们来一起学习下. 提交订单有几个关键点: 1, 用户必须登录2, 购物车必须要有购物项3, 购物车中购物项库存必须小于库存4, 结算成功, 清理购物车(这个只清理购物车中已经结算的购物项) 接下来我们再来看下订单相关的两张表的设计:订单表订单详情表在这里我们可以发现 订单表和 我们的购物车很像, 订单详情表和我们的购物车中的购物项很像. 明白了这些原理后我们就来看下代码的具

购物车特效-贝塞尔曲线动画(点击添加按钮的进候,产生抛物线动画效果)

demo效果: l 购物车特效原理: 1.从添加按钮获取开始坐标 2.从购物车图标获取结束坐标 3.打气一个视图,添加属性动画ObjectAnimator(缩小),ValueAnimator(路线) 4.动画开始时添加该视图,动画结束删除该视图 5.运动路径使用TypeEvaluator与贝塞尔函数计算 activity布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" an

[项目构建 十五]babasport 项目总结及源码分享.

终于把这个项目自己手动的敲了一遍且总结了其中的知识点, 现在来做一个整体性的总结. 总目录: [项目构建 一]babasport 项目环境搭建. [项目构建 二]babasport SSM 三大框架整合 [项目构建 三]babasport Dubbo的使用及浅析. [项目构建 四]babasport 分页的使用及解析. [项目构建 五]babasport ajax图片上传及FastDFS入门案例. [项目构建 六]babasport Mybatis逆向工程构建项目实例. [项目构建 六]baba

[Java面经] 关于面试的二三事.

今天终于闲下来了, 那么也好总结下这几天面试的经历.四天的时间一共面了七家, 有一家是自己推迟了没有去.声明:如若转载请注明出处:http://www.cnblogs.com/wang-meng/p/5895787.html因为我之前的博文我发现很多被转载都是没有出处的, 直接复制粘贴就变成了他们的产物.. 先总结下这么几次面试下来的感受: 1, 先了解市场行情,给出自己的市场定位了解你所找工作 的一些市场行情, 这样你就知道自己的一个水平是可以拿到一个什么价位了.因为基本上每家公司都会提前对你

php面试全套

7.mvc是什么?相互间有什么关系? 答:mvc是一种开发模式,主要分为三部分:m(model),也就是模型,负责数据的操作;v(view),也就是视图,负责前后台的显示;c(controller),也就是控制器,负责业务逻辑 客户端请求项目的控制器,如果执行过程中需要用到数据,控制器就会到模型中获取数据,再将获取到的数据通过视图显示出来 8.oop是什么? 答:oop是面向对象编程,面向对象编程是一种计算机编程架构,OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而

【千纸诗书】—— PHP/MySQL二手书网站后台开发之知识点记录

前言:使用PHP和MySQL开发后台管理系统的过程中,发现有一些通用的[套路小Tip],这里集中记录一下.结合工作中ing的后台业务,我逐渐体会到:除了技术知识外.能使用户体验好的“使用流程设计”积累也十分重要╭( ???)? ?? 项目github地址:https://github.com/66Web/php_book_store,欢迎Star. 一.知识点记录 1.数据库的表名和列名 绝对不要和数据库的关键字相同  order  order by 订单表-indent   分类表-class