Day-18-购物车模块的实现,商品的加购和删除,登录以后才可以查看购物车,订单等

购物车模块的实现

1-编辑POJO对象

@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo{
    
    @TableId(type = IdType.AUTO)
    private Long id;
    private Long userId;
    private Long itemId;
    private String itemTitle;
    private String itemImage;
    private Long itemPrice;
    private Integer num;

}

2-创建购物车项目

2.2.1 添加继承/依赖/插件

<dependencies>
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--添加插件 有main方法时 需要添加插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

2.2.2 业务结构

在这里插入图片描述

2.3 展现购物车列表

2.3.1 业务说明

说明: 当用户点击购物车按钮时,应该跳转到购物车展现页面cart.jsp
url如下: http://www.jt.com/cart/show.html

2.3.2 编辑CartController

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.service.DubboCartService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/cart")
public class CartController {

    @Reference(check = false)
    private DubboCartService cartService;

    /**
     * 展现购物车列表信息  根据userId查询购物车记录
     * url: http://www.jt.com/cart/show.html
     * 参数: 根据userId查询购物车数据信息
     * 返回值: 购物车展现页面
     * 页面取值方式: ${cartList}
     */
    @RequestMapping("/show")
    public String show(Model model){
        long userId = 7L;   //暂时写死  后期维护
        List<Cart> cartList = cartService.findCartListByUserId(userId);
        //利用model对象将数据保存到request对象中
        model.addAttribute("cartList",cartList);
        return "cart";
    }

}


2.3.2 编辑CartService

package com.jt.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.CartMapper;
import com.jt.pojo.Cart;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@Service(timeout = 3000)
public class DubboCartServiceImpl implements DubboCartService{

    @Autowired
    private CartMapper cartMapper;


    @Override
    public List<Cart> findCartListByUserId(long userId) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id", userId);
        return cartMapper.selectList(queryWrapper);
    }
}


2.4 购物车新增操作,

用户如果重复加购? 只做数量的更新

2.4.1 页面分析

1.页面结构分析
在这里插入图片描述
2.加入购物车按钮

<a class="btn-append " id="InitCartUrl" onclick="addCart();" clstag="shangpin|keycount|product|initcarturl">加入购物车<b></b></a>

3.点击事件

		//利用post传值
		function addCart(){
			var url = "http://www.jt.com/cart/add/${item.id}.html";
			document.forms[0].action = url;		//js设置提交链接
			document.forms[0].submit();			//js表单提交
		}

4.form表单分析

<form id="cartForm" method="post">
									<input class="text" id="buy-num" name="num" value="1" onkeyup="setAmount.modify('#buy-num');"/>
									<input type="hidden" class="text"  name="itemTitle" value="${item.title }"/>
									<input type="hidden" class="text" name="itemImage" value="${item.images[0]}"/>
									<input type="hidden" class="text" name="itemPrice" value="${item.price}"/>
								</form>

2.4.2 编辑CartController

 /**
     * 业务说明:  实现用户购物车数据新增
     * url: http://www.jt.com/cart/add/1474391990.html
     * 参数: 购物车表单提交  Cart对象
     * 返回值: 重定向到跳转到购物车展现页面
     *
     * 扩展内容: 如果restFul的参数,与对象的属性名称一致,则可以直接赋值
     */
    @RequestMapping("/add/{itemId}")
    public String addCart(Cart cart){
        long userId = 7;
        cart.setUserId(userId);
        cartService.addCart(cart);
        return "redirect:/cart/show.html";
    }

2.4.3 编辑CartService

 /**
     * 难点: 用户如果重复加购? 只做数量的更新
     * 业务操作:
     *      1.根据userId/itemId查询数据库检查是否加购.
     *      有值: 已经加购 则只更新数量
     *      没有值: 第一次加购 则直接入库即可.
     * @param cart
     */
    @Override
    public void addCart(Cart cart) {
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", cart.getUserId());
        queryWrapper.eq("item_id", cart.getItemId());
        Cart cartDB = cartMapper.selectOne(queryWrapper);
        if(cartDB == null){  //说明用户第一次加购
            cartMapper.insert(cart);
        }else{
            //说明用户之间添加过该商品  数量的更新
            int num = cart.getNum() + cartDB.getNum();
            Cart temp = new Cart();
            temp.setNum(num).setId(cartDB.getId());
            //根据id 更新对象中不为null的数据...
            cartMapper.updateById(temp);
        }
    }

3. 如果是已加购的,只做数量更新操作

3.1页面分析
1).页面URL分析
在这里插入图片描述
2).页面html分析

<div class="quantity-form" data-bind="">
    <a href="javascript:void(0);" class="decrement" clstag="clickcart|keycount|xincart|diminish1" id="decrement">-</a>
    <input type="text" class="quantity-text" itemPrice="${cart.itemPrice}" itemId="${cart.itemId}" value="${cart.num }" id="changeQuantity-11345721-1-1-0">
    <a href="javascript:void(0);" class="increment" clstag="clickcart|keycount|xincart|add1" id="increment">+</a>
</div>

3).页面JS

$(".increment").click(function(){//+
			var _thisInput = $(this).siblings("input");
			_thisInput.val(eval(_thisInput.val()) + 1);
			$.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val(),function(data){
				TTCart.refreshTotalPrice();
			});
		});

3.2 编辑CartController

/**
     * 购物车数量更新操作
     * URL地址: http://www.jt.com/cart/update/num/1474391990/16
     * 参数:    itemId,num
     * 返回值:  没有 void
     */
    @RequestMapping("/update/num/{itemId}/{num}")
    @ResponseBody //将返回值转化为json   代表ajax程序结束
    public void updateNum(Cart cart){

        long userId = 7;
        cart.setUserId(userId);
        cartService.updateNum(cart);
    }

3.3 编辑CartService

 //sql: update tb_cart set num=#{num},updated=#{updated} where user_id=#{userId} and
    //     item_id = #{itemId}
    @Override
    public void updateNum(Cart cart) {
        Cart temp = new Cart();
        temp.setNum(cart.getNum());
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id", cart.getUserId());
        queryWrapper.eq("item_id", cart.getItemId());
        cartMapper.update(temp,queryWrapper);
    }

4.购物车删除操作

4.1页面分析

业务说明: 当用户点击删除按钮时,应该重定向到购物车展现页面.
在这里插入图片描述

4.2

4.3 编辑CartController

 /**
     * URL地址:http://www.jt.com/cart/delete/1474391990.html
     * 返回值:  String类型
     */
    @RequestMapping("/delete/{itemId}")
    public String deleteCart(Cart cart){

        long userId = 7;
        cart.setUserId(userId);
        cartService.deleteCart(cart);
        return "redirect:/cart/show.html";
    }

4.4编辑CartService

  @Override
    public void deleteCart(Cart cart) {
        //根据对象中不为null的属性充当where条件
        cartMapper.delete(new QueryWrapper<>(cart));
    }

5. 关于前台权限控制

5.1 业务说明

当用户在没有登录的条件下,不允许访问敏感业务数据例如购物车/订单业务等…
难点:
1.如何判断用户是否登录? 1.检查cookie 2.检查redis
2.如何控制权限? 拦截器!

5.1.1 拦截器业务实现原理
5.1.2 SpringMVC流程图复习

在这里插入图片描述

5.3 拦截器工作流程

在这里插入图片描述

5.4修改jt-web中的MVC的配置文件

配置拦截器在这里插入图片描述

5.5jt-web中新建拦截器 UserInterceptor

编辑拦截器接口

package com.jt.interceptor;

import com.jt.pojo.User;
import com.jt.util.CookieUtil;
import com.jt.util.ObjectMapperUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import redis.clients.jedis.JedisCluster;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.function.Predicate;
@Component  //将对象交给Spring容器管理
public class UserInterceptor implements HandlerInterceptor {

    @Autowired
    private JedisCluster jedisCluster;

    /**
     * 通过拦截器实现拦截,重定向系统登录页面
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     *
     * 返回值说明:
     *      boolean   false 表示拦截 一般配合重定向方式使用
     *
     * 业务调用:
     *      1.获取cookie中的数据
     *      2.检查redis中是否有数据
     *      3.校验用户是否登录.
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.获取cookie中的数据,检查是否登录
        String ticket = CookieUtil.getCookieValue(request, "JT_TICKET");
        if(StringUtils.hasLength(ticket) && jedisCluster.exists(ticket)){//判断数据是否有值
                //2.动态获取user信息
                String json = jedisCluster.get(ticket);
                //3.将json转化为用户对象
                User user = ObjectMapperUtil.toObj(json, User.class);
                request.setAttribute("JT_USER", user);
                return true;    //表示程序放行
        }

        //实现用户重定向
        response.sendRedirect("/user/login.html");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

        request.removeAttribute("JT_USER");
    }
}


5.6修改编辑CartController

在这里插入图片描述

ThreadLocal

6.ThreadLocal作用

名称: 本地线程变量
作用: 在同一个线程内,实现数据共享.
在这里插入图片描述

6.1封装工具API

package com.jt.util;

import com.jt.pojo.User;

public class UserThreadLocal {
    //线程的一个属性  ThreadLocal是线程安全的
    private static ThreadLocal<User> threadLocal = new ThreadLocal<>();

    public static void set(User user){
        threadLocal.set(user);
    }

    public static User get(){

        return threadLocal.get();
    }

    public static void remove(){

        threadLocal.remove();   //删除数据
    }
}


6.2 基于ThreadLocal实现数据取赋值操作

1.拦截器赋值
在这里插入图片描述
2.用户取值在这里插入图片描述
3.数据销毁在这里插入图片描述

总结:

购物车模块实现步骤:

1 -建一个购物车POJO对象
2-使用Dubbo+zk进行jt-web(消费者)和jt-cart(提供者)
3-点击购物车按钮时候,跳转到购物车界面: 根据userId查询购物车数据信息,并把数据渲染到购物车页面
4-添加到购物车:
1) 商品未加购,执行新增操作入库
2) 商品已加购,获取该商品的购物信息,只需要更新数量

控制层CartController代码的实现:

(扩展内容: 如果restFul的参数,与对象的属性名称一致,则可以直接赋值)
@RequestMapping("/add/{itemId}")
public String addCart(Cart cart){
    long userId = 7;//后期用localThread维护
    cart.setUserId(userId);
    cartService.addCart(cart);
    return "redirect:/cart/show.html";
}

业务层CartServiceImpl代码的实现:

难点: 用户如果重复加购? 只做数量的更新
业务操作:
1.根据userId/itemId查询数据库检查是否加购.
有值: 已经加购 则只更新数量
没有值: 第一次加购 则直接入库即可.
把前端传过来的cart参数用构造器QueryWrapper进行eq字段比较如下

	 QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
	 queryWrapper.eq("user_id", cart.getUserId());
	 queryWrapper.eq("item_id", cart.getItemId());
	 Cart cartDB = cartMapper.selectOne(queryWrapper);//要么是null,说明购物车内未加购过,要么是有数据,说明加购过.
	    然后进行判断:
	
	  if(cartDB == null){  //说明用户第一次加购
	            cartMapper.insert(cart);
	        }else{
	            //说明用户之间添加过该商品  数量的更新
	            int num = cart.getNum() + cartDB.getNum();
	            Cart temp = new Cart();
	            temp.setNum(num).setId(cartDB.getId());
	            //根据id 更新对象中不为null的数据...
	            cartMapper.updateById(temp);
	        }

2-已加购的话进行数量的更新就可以

实现思路:先从本地线程获取到对应的购物车,然后再更新数量就可以
控制层CartController
利用本地线程localThead 获取共享数据即可以获得用户的id,根据userId查询对应的用户购物车,然后直接更新数量

/**
     * 购物车数量更新操作
     * URL地址: http://www.jt.com/cart/update/num/1474391990/16
     * 参数:    itemId,num
     * 返回值:  没有 void
     */
    @RequestMapping("/update/num/{itemId}/{num}")
    @ResponseBody //将返回值转化为json   代表ajax程序结束
    public void updateNum(Cart cart){

        long userId = 7;
        cart.setUserId(userId);
        cartService.updateNum(cart);
    }

编辑CartService
1-重新new一个购物车,获取到数量,
根据控制层的购物车进行数量的更新即可.

 //sql: update tb_cart set num=#{num},updated=#{updated} where user_id=#{userId} and
    //     item_id = #{itemId}
    @Override
    public void updateNum(Cart cart) {
        Cart temp = new Cart();
        temp.setNum(cart.getNum());
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id", cart.getUserId());
        queryWrapper.eq("item_id", cart.getItemId());
        cartMapper.update(temp,queryWrapper);
    }

重点难点:

1-用户如果重复加购? 只做数量的更新

2-如何进行前台的控制

当用户在没有登录的条件下,不允许访问敏感业务数据例如购物车/订单业务等…
难点:
1.如何判断用户是否登录? 1.检查cookie 2.检查redis
2.如何控制权限? MVC拦截器!

3-使用ThreadLocal实现统一线程内数据共享

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香瓜西蕉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值