Day-18-购物车模块的实现,商品的加购和删除,登录以后才可以查看购物车,订单等_香瓜西蕉的博客-程序员宅基地_html 商品列表

购物车模块的实现

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实现统一线程内数据共享

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/czx1254678152/article/details/114625337

智能推荐

串口、COM口、TTL、RS-232的区别详解_You_Never_Come_Here的博客-程序员宅基地

1、串口、COM口是指的物理接口形式(硬件)。而TTL、RS-232、RS-485是指的电平标准(电信号)。  2、接设备的时候,一般只接GND RX TX。不会接Vcc或者+3.3v的电源线,避免与目标设备上的供电冲突。  3、PL2303、CP2102芯片是 USB 转 TTL串口 的芯片,用USB来扩展串口(TTL电平)。  4、MAX232芯片是 TTL电平与RS2

《Unity3D网络游戏实战》第2章_yxqq378287007的博客-程序员宅基地

《Unity3D网络游戏实战》第2章异步代码异步客户端异步代码Async.csusing System;using System.Threading;namespace Async { class MainClass { public static void Main (string[] args) { Timer timer = new Timer(Timeout, null, 2000, 0); Thread.Sleep(2000*2); Console.WriteL

安装系统_iefanrui的博客-程序员宅基地

第一步、准备工作    安装系统前要做一些准备工作,首先是制作你要安装的系统的系统镜像。制作系统镜像要先下载一个UltraISO软件。然后右键点击选择“以管理员的身份运行”(注意:必须这样做)。打开后点击左上角的“文件”-—“打开”,找到存放系统镜像的目录,选中系统镜像,然后点击“打开”。然后点击 “启动”—“开始硬盘录入”,然后选择一个U盘作为系统启动盘(注意:这个U盘必须足够大,一般16G的就...

pv3d 的 Camera3D练习_suzhou_boy1的博客-程序员宅基地

 http://www.sandy1219.com/3d/test2/testflabcamera.html  package{ import flab3d.FlabCamera3D; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.Stage

CAsyncSocket::Send()、OnSend()_hahahapeige的博客-程序员宅基地

virtual int Send( const void* lpBuf, int nBufLen, int nFlags = 0);Dialog中Socket设置AsyncSelect(FD_WRITE),触发虚函数OnSend(),之后调用Send()发送消息。参数lpBuf包含要传输的数据的缓冲区。nBufLen中的数据的长度lpBuf以字节为单位。nFlags...

随便推点

SD省队集训2019Day8之“有没有空”_weixin_30917213的博客-程序员宅基地

有没有空(busy)([Ynoi2018]天降之物)给你一个长为 n 的序列 a你需要实现 m 个操作,操作有两种:1.把序列中所有值为 x 的数的值变成 y2.找出一个位置 i 满足 ai==x,找出一个位置 j 满足 aj==y,使得|i-j|最小,并输出|i-j|部分分:二分考虑把整个区间分成两部分,那么这两个数要么都在左边,要么都在右边,要么一左一右。前两种情况可以递归解决,同...

关于PAT配置_赵文超z的博客-程序员宅基地

PAT配置 问题 在R1通过PAT配置实现企业内网192.168.0.0/24复用f0/1端口 方案网络拓扑如图-3所示:图-3 步骤实现此案例需要按照如下步骤进行。步骤一:基于端口的PAT配置限制1)删除动态NAT配置tarena-R1(config)#no ip nat inside source list 1tarena-R1(config)#no ip n...

pthread笔记_银龙w的博客-程序员宅基地

特点:有joinable和detached两种类型的线程。joinable(默认)可以被其他线程回收和杀死,但其存储器、资源不会在显式和隐式退出后被回收。detached不可以被回收和杀死,但其资源会在结束后自动回收。 线程属性可以存在pthread_attr_t类型的变量中,它包含着一个线程可以设置的所有属性,并需要初始化才能使用。同理,互斥锁和条件变量属性使用类pthread_mutexa...

解决zabbix中文不能导入数据库和图形中文乱码的问题_运维饺子的博客-程序员宅基地

一.解决中文不能导入:先说以下没安装之前,正常的解决方法:设置数据库 :vim /etc/my.cnf在[mysqld]下添加:character_set_server=utf8并且在创建zabbix库的时候,设置utf8:create database zabbix character set utf8;以上。然后再说以下已经安装完了出现如下错误的解决方法:导出数据库:...

推荐文章

热门文章

相关标签