SpringBoot电脑商城-购物车

1. 加入购物车

在这里插入图片描述
在这里插入图片描述

1.1 创建数据库表

CREATE TABLE t_cart (
	cid INT AUTO_INCREMENT COMMENT '购物车数据id',
	uid INT NOT NULL COMMENT '用户id',
	pid INT NOT NULL COMMENT '商品id',
	price BIGINT COMMENT '加入时商品单价',
	num INT COMMENT '商品数量',
	created_user VARCHAR(20) COMMENT '创建人',
	created_time DATETIME COMMENT '创建时间',
	modified_user VARCHAR(20) COMMENT '修改人',
	modified_time DATETIME COMMENT '修改时间',
	PRIMARY KEY (cid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.2 创建实体类

public class Cart extends BaseEntity{
    private Integer cid;
    private Integer uid;
    private Integer pid ;
    private Long price;
    private Integer num;
    //...

1.3 持久层

  • 规划需要执行的SQL语句
    1.向购物车表中插入数据
    insert into t_cart () values ()
    
    2.如果当前商品已经在购物车中存在,则直接更新num的数量即可。
    update t_cart set num = ? where cid=?
    
    3.在插入或更新具体执行哪个语句,取决于数据库中是否有当前的这个购物车商品的数据,得去查询才能确定。
    select * from t_cart where cid = ? and uid = ?
    
  • 设计接口和抽象方法
    创建一个CartMapper接口持久层的文件。
    public interface CartMapper {
       //插入购物车数据
       Integer insert(Cart cart);
    
       //更新购物车某件商品的数量
       Integer updateNumByCid(Integer cid, Integer num,
                      String modifiedUser, Date modifiedTime);
    
       //根据用户的id和商品的id来查询购物车的数据
       Cart findByUidAndPid(Integer uid, Integer pid);
    }
    
  • SQL映射
    创建一个CartMapper.xml映射文件,添加以上三个抽象方法的SQL语句映射。
    <?xml version="1.0" encoding="UTF8" ?>
    <!DOCTYPE mapper
           PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
           "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.cy.store.mapper.CartMapper">
    
       <resultMap type="com.cy.store.entity.Cart" id="CartEntityMap">
           <id property="cid" column="cid"/>
           <result property="createdUser" column="created_user"/>
           <result property="createdTime" column="created_time"/>
           <result property="modifiedUser" column="modified_user"/>
           <result property="modifiedTime" column="modified_time"/>
       </resultMap>
    
       <insert id="insert" useGeneratedKeys="true" keyProperty="cid">
           insert into t_cart (uid, pid, price, num, created_user, created_time, modified_user, modified_time)
           values (#{uid}, #{pid}, #{price}, #{num}, #{createdUser},#{createdTime},#{modifiedUser},#{modifiedTime})
       </insert>
    
       <update id="updateNumByCid">
           update t_cart
           set
               num=#{num}, modified_user=#{modifiedUser}, modified_time=#{modifiedTime}
           where
               cid=#{cid}
       </update>
    
       <select id="findByUidAndPid" resultMap="CartEntityMap">
           select * from t_cart where uid=#{uid} and pid=#{pid}
       </select>
    
    </mapper>
    
    测试
    @Autowired
    private CartMapper cartMapper;
    
    @Test
    public void insert(){
        Cart cart = new Cart();
        cart.setUid(10);
        cart.setPid(10000011);
        cart.setNum(2);
        cart.setPrice(1000L);
        cartMapper.insert(cart);
    }
    
    @Test
    public void updateNumByCid(){
        cartMapper.updateNumByCid(1,4,"张三", new Date());
    }
    
    @Test
    public void findByUidAndPid() {
        System.out.println(cartMapper.findByUidAndPid(10, 10000011));
    }
    

1.4 业务层

  • 异常规划
    1.插入数据产生的异常:InsertException
    2.更新数据产生的异常:UpdateException
  • 接口和抽象方法
    创建一个ICartService接口文件
    public interface ICartService {
       /**
        * 添加商品到购物车
        * @param uid 用户id
        * @param pid 商品id
        * @param amount 新增数量
        * @param username 用户名(修改者)
        */
       void addToCart(Integer uid, Integer pid, Integer amount, String username);
    }
    
  • 实现接口
    创建一个CartServiceImpl的实现类
    @Override
    public void addToCart(Integer uid, Integer pid, Integer amount, String username) {
        //查询当前要添加的这个物品是否在表中已存在
        Cart result = cartMapper.findByUidAndPid(uid, pid);
        Date date = new Date();
        if(result == null) { //表示这个商品从来没有被添加到购物车中,则进行新增操作
            Cart cart = new Cart();
    
            cart.setUid(uid);
            cart.setPid(pid);
            cart.setNum(amount);
            //补全价格,来自于商品中的数据
            Product product = productMapper.findById(pid);
            cart.setPrice(product.getPrice());
            //补全4项日志
            cart.setCreatedUser(username);
            cart.setCreatedTime(date);
            cart.setModifiedUser(username);
            cart.setModifiedTime(date);
    
            Integer rows = cartMapper.insert(cart);
            if(rows != 1) {
                throw new InsertException("插入数据时产生未知的异常");
            }
        } else { //表示当前的商品在购物车中已经存在,则更新到这条数据的num值
            Integer num = result.getNum() + amount;
            Integer rows = cartMapper.updateNumByCid(
                    result.getCid(),
                    num,
                    username,
                    date
            );
            if(rows != 1) {
                throw new UpdateException("更新数据时产生未知的异常");
            }   
        }
    }
    
    测试
    @Autowired
    private ICartService cartService;
    
    @Test
    public void addToCart() {
        cartService.addToCart(10,10000003,5,"管理员");
    }
    

1.5 控制层

  • 没有需要处理的异常
  • 设计请求处理
    /carts/add_to_cart
    get
    pid,amount,session
    JsonResult<Void>
    
  • 完成请求处理方法的编写。创建一个CartController类。
    @RequestMapping("carts")
    @RestController
    public class CartController extends BaseController{
       @Autowired
       private ICartService cartService;
    
       @RequestMapping("add_to_cart")
       public JsonResult<Void> addToCart(
                                   Integer pid,
                                   Integer amount,
                                   HttpSession session) {
           cartService.addToCart(getuidFromSession(session),pid,amount,getUsernameFromSession(session));
           return new JsonResult<>(OK);
       }
    }
    
    先登录再访问进行测试:http://localhost:8080/carts/add_to_cart?pid=10000021&amount=5

1.6 前端页面

在ajax函数中data参数的数据设置的方式:

  • data: #("form表单选择").serialize():用于参数比较多,并且表单的参数都需要提交
  • data: new FormData($("form表单选择")[0]):用于提交文件
  • data: "username=Tom":用于参数值固定并且参数值列表有限
  • 用JSON格式提交:
    data: {
    	"username": "TOM",
    	"age": 18,
    	"sex": 0
    }
    

在product.html页面,给[加入购物车]按钮添加点击事件,并发送ajax请求。

$("#btn-add-to-cart").click(function () {
	$.ajax({
		url: "/carts/add_to_cart",
		type: "post",
		data: {
			"pid": id,
			"amount": $("#num").val()
		},
		dataType: "JSON",
		success: function (json) {
			if(json.state == 200) {
				alert("加入购物车成功");

			} else {
				alert("加入购物车失败");
			}
		},
		error: function (xhr) {
			alert("加入购物车时产生未知的异常" + xhr.message);
		}
	});
});

2. 显示购物车

在这里插入图片描述
登录后将对应用户的购物车数据展示出来。

2.1 持久层

  • 规划SQL语句

    select
    	cid,uid,pid,t_cart.price,t_cart.num,
    	t_product.title,t_product.image,t_product.price as realPrice
    from
    	t_cart left join t_product on t_cart.pid = t_product.id
    where 
    	uid = ?
    order by
    	t_cart.created_time desc;
    

    VO:Value Object,值对象。当进行select查询时,查询的结果属于多张表中的内容,此时发现结果集不能直接使用某个pojo实体类来接收,pojo实体类不能包含多表查询出来的结果。解决方式是:重新构建一个新的对象,这个对象用于存储所查询出来的结果集对应的映射,所以把这个对象称之为 值对象

    在store包下创建一个vo包,在vo包下创建CartVO实体类:

    /** 购物车数据的VO类 */
    public class CartVO implements Serializable {
       private Integer cid;
       private Integer uid;
       private Integer pid;
       private Long price;
       private Integer num;
       private String title;
       private String image;
       private Long realprice;
       //...
    
  • 设计接口
    在CartMapper接口中定义抽象方法

    List<CartVO> findVOByUid(Integer uid);
    
  • 映射SQL

    <select id="findVOByUid" resultType="com.cy.store.vo.CartVO">
        select
            cid, uid, pid, t_cart.price, t_cart.num,
            t_product.title, t_product.image, t_product.price as realPrice
        from
            t_cart left join t_product on t_cart.pid = t_product.id
        where
            uid = #{uid}
        order by
            t_cart.created_time desc;
    </select>
    

    测试

    @Test
    public void findVOByUid() {
        System.out.println(cartMapper.findVOByUid(10));
    }
    

2.2 业务层

  • 编写业务层的接口方法
    List<CartVO> getVOByUid(Integer uid)
    
  • 在实现类中实现此方法
    @Override
    public List<CartVO> getVOByUid(Integer uid) {
        return cartMapper.findVOByUid(uid);
    }
    

2.3 控制层

  • 设计请求
    /carts/
    session
    get
    JsonResult<List<CartVO>>
    
  • 实现请求处理方法的代码
    @RequestMapping({"","/"})
    public JsonResult<List<CartVO>> getVOByUid(HttpSession session) {
        List<CartVO> data = cartService.getVOByUid(getuidFromSession(session));
        return new JsonResult<>(OK, data);
    }
    
    先登录再测试:http://localhost:8080/carts

2.4 前端页面

1.注释掉cart.js文件

<!-- <script src="../js/cart.js" type="text/javascript" charset="utf-8"></script> -->

2.注意form表单结构。将“结算按钮”改成type="button"属性值。
3.ready()函数来完成自动的ajax请求的提交和处理。

<script type="text/javascript">
	$(document).ready(function () {
		showCartList();
	});
	/** 展示购物车列表数据*/
	function showCartList() {
		//清空tbody标签的数据
		$("#cart-list").empty();
		$.ajax({
			url: "/carts",
			type: "get",
			dataType: "JSON",
			success: function (json) {
				let list = json.data;
				for (let i = 0; i < list.length; i++) {
					let tr = '<tr>\n' +
							'<td>\n' +
							'<input name="cids" value="#{cid}" type="checkbox" class="ckitem" />\n' +
							'</td>\n' +
							'<td><img src="..#{image}collect.png" class="img-responsive" /></td>\n' +
							'<td>#{title}#{msg}</td>\n' +
							'<td>¥<span id="goodsPrice#{cid}">#{singlePrice}</span></td>\n' +
							'<td>\n' +
							'<input id="price-#{cid}" type="button" value="-" class="num-btn" οnclick="reduceNum(1)" />\n' +
							'<input id="goodsCount#{cid}" type="text" size="2" readonly="readonly" class="num-text" value="#{num}">\n' +
							'<input id="price+#{cid}" class="num-btn" type="button" value="+" οnclick="addNum(1)" />\n' +
							'</td>\n' +
							'<td><span id="goodsCast#{cid}">#{totalPrice}</span></td>\n' +
							'<td>\n' +
							'<input type="button" οnclick="delCartItem(this)" class="cart-del btn btn-default btn-xs" value="删除" />\n' +
							'</td>\n' +
							'</tr>'
					tr = tr.replace(/#{cid}/g, list[i].cid);
					tr = tr.replace(/#{image}/g, list[i].image);
					tr = tr.replace(/#{title}/g, list[i].title);
					tr = tr.replace(/#{msg}/g, list[i].realPrice);
					tr = tr.replace(/#{num}/g, list[i].num);
					tr = tr.replace(/#{singlePrice}/g, list[i].price);
					tr = tr.replace(/#{totalPrice}/g, list[i].price*list[i].num);
					$("#cart-list").append(tr);
				}
			},
			error: function (xhr) {
				alert("购物袋列表数据加载产生未知的异常" + xhr.status);
			}
		});
	}
</script>

3. 增加购物车商品数量

在这里插入图片描述

3.1 持久层

  • 规划需要执行的SQL语句
    1.执行更新t_cart表记录的num的值,无需重复开发。
    update t_cart set num = ?, modified_user = ?, modified_time = ? where cid = ?;
    
    2.根据cid的值来查询当前的购物车这条数据是否存在
    select * from t_cart where cid=#{cid}
    
  • 接口和抽象方法
    Cart findByCid(Integer cid);
    
  • 配置SQL的映射
    <select id="findByCid">
        select * from t_cart where cid=#{cid};
    </select>
    
    测试
    @Test
    public void findByCid() {
        System.out.println(cartMapper.findByCid(1));
    }
    

3.2 业务层

  • 规划异常
    1.在更新时会产生更新异常
    2.查询的数据是否有访问的权限
    3.要查询的数据不存在,抛出CartNotFoundException异常。
  • 设计接口和抽象方法
    /**
     * 更新用户的购物车数据的数量
     * @param cid
     * @param uid
     * @param username
     * @return 增加成功后新的数量
     */
    Integer addNum(Integer cid, Integer uid, String username);
    
  • 实现方法
    @Override
    public Integer addNum(Integer cid, Integer uid, String username) {
        Cart result = cartMapper.findByCid(cid);
        if(result == null) {
            throw new CartNotFoundException("数据不存在");
        }
        if(!result.getUid().equals(uid)) {
            throw new AccessDeniedException("数据非法访问");
        }
        Integer num = result.getNum() + 1;
        Integer rows = cartMapper.updateNumByCid(cid, num, username, new Date());
        if(rows != 1) {
            throw new UpdateException("更新数据失败!");
        }
        return num;
    }
    

3.3 控制层

  • 处理异常
    else if (e instanceof CartNotFoundException) {
        result.setState(4007);
        result.setMessage("购物车数据不存在的异常");
    }
    
  • 设计请求
    /carts/{cid}/num/add
    Integer cid, HttpSession
    post
    JsonResult<Integer>
    
  • 处理请求
    @RequestMapping("{cid}/num/add")
    public JsonResult<Integer> addNum(@PathVariable("cid") Integer cid, HttpSession session) {
        Integer data = cartService.addNum(
                cid,
                getuidFromSession(session),
                getUsernameFromSession(session)
        );
        return new JsonResult<>(OK, data);
    }
    
    先登录再访问url:http://localhost:8080/carts/1/num/add

3.4 前端页面

function addNum(cid) {
	$.ajax({
		url: "/carts/" + cid + "/num/add",
		type: "post",
		dataType: "JSON",
		success: function (json) {
			if(json.state == 200) {
				$("#goodsCount" + cid).val(json.data);
				let price = $("#goodsPrice" + cid).html();
				let totalPrice = price * json.data;
				$("#goodsCast" + cid).html(totalPrice);
			} else {
				alert("增加购物车数据失败," + json.message);
			}
		},
		error: function (xhr) {
			alert("增加购物车商品数量产生未知的异常" + xhr.message);
		}
	});
}

4. 显示勾选购物车数据

4.1 持久层

  • 规划SQL语句
    用户在购物车列表页中通过随机勾选相关的商品,在点击“结算”按钮后,跳转到结算页面,在这个页面中需要展示用户在上个页面所勾选的购物车对应的数据。两个页面需要用户勾选的多个cid传递给下一个页面。
    select
    	cid,uid,pid,t_cart.price,t_cart.num,
    	t_product.title,t_product.image,t_product.price as realPrice
    from
    	t_cart left join t_product on t_cart.pid = t_product.id
    where 
    	cid in (?,?,?)
    order by
    	t_cart.created_time desc;
    
  • 接口和抽象方法
    List<CartVO> findVOByCid(Integer[] cids);
    
  • SQL映射
    <select id="findVOByCid" resultType="com.cy.store.vo.CartVO">
        select
            cid, uid, pid, t_cart.price, t_cart.num,
            t_product.title, t_product.image, t_product.price as realPrice
        from
            t_cart left join t_product on t_cart.pid = t_product.id
        where
            cid in (
                <foreach collection="array" item="cid" separator=",">
                    #{cid}
                </foreach>
            )
        order by
            t_cart.created_time desc;
    </select>
    
    测试
    @Test
    public void findVOByCid() {
        Integer[] cids = {1,2,3,4,30,20,40};
        System.out.println(cartMapper.findVOByCid(cids));
    }
    

4.2 业务层

1.没有需要进行异常的规划
2.设计业务层接口中抽象方法

List<CartVO> getVOByCid(Integer uid, Integer[] cids);

3.完成抽象方法的设计

@Override
public List<CartVO> getVOByCid(Integer uid, Integer[] cids) {
    List<CartVO> list = cartMapper.findVOByCid(cids);
    Iterator<CartVO> it = list.iterator();
    while(it.hasNext()) {
        CartVO cartVO = it.next();
        if(!cartVO.getUid().equals(uid)) { //表示这个数据不属于当前对象
            //从集合中移除这个数据
            list.remove(cartVO);
        }
    }
    return list;
}

4.3 控制层

1.请求设计

/carts/list
Integer cids, HttpSession session
post
JsonResult<CartVO>

2.完成请求处理方法的定义和声明

@RequestMapping("list")
public JsonResult<List<CartVO>> getVOByCid(Integer[] cids, HttpSession session) {
    List<CartVO> data = cartService.getVOByCid(getuidFromSession(session),cids);
    return new JsonResult<>(OK, data);
}

4.4 前端页面

在这里插入图片描述

在cart.html中有个表单,点击“结算”按钮跳转到这个页面:action=“orderConfirm.html”。在orderConfirm.html页面加入如下代码,可以使页面跳转后就加载要结算的数据。

<script type="text/javascript">
	$(document).ready(function () {
		showCartList();
	});
	//展示购物车列表
	function showCartList() {
		//清空tbody标签的数据
		$("#cart-list").empty();
		$.ajax({
			url: "/carts/list",
			type: "get",
			data: location.search.substr(1),
			dataType: "JSON",
			success: function (json) {
				if(json.state == 200) {
					let list= json.data;
					let allCount = 0;
					let allPrice = 0;
					for (let i = 0; i < list.length; i++) {
						let tr = '<tr>\n' +
								'<td><img src="..#{image}collect.png" class="img-responsive" /></td>\n' +
								'<td>#{title}</td>\n' +
								'<td>¥<span>#{price}</span></td>\n' +
								'<td>#{num}</td>\n' +
								'<td><span>#{totalPrice}</span></td>\n' +
								'</tr>';
						tr = tr.replace(/#{image}/g, list[i].image);
						tr = tr.replace(/#{title}/g, list[i].title);
						tr = tr.replace(/#{price}/g, list[i].price);
						tr = tr.replace(/#{num}/g, list[i].num);
						tr = tr.replace(/#{totalPrice}/g, list[i].price*list[i].num);
						$("#cart-list").append(tr);

						allCount += list[i].num;
						allPrice += list[i].price * list[i].num;
					}
					$("#all-count").html(allCount);
					$("#all-price").html(allPrice);
				}
			},
			error: function (xhr) {
				alert("购物袋列表数据加载产生未知的异常" + xhr.status);
			}
		});
	}
</script>

注:这里有个bug,当你什么都不勾选就去结算,会报错。因为controller中是需要接收参数的,但是没勾选就提交是没有带参数的,这就有问题了。所以最好在结算的时候判断一下有没有选择商品。

4.5 购物车页面显示收货地址列表

在这里插入图片描述

1.收获地址存放在一个select下拉列表中,将查询到的当前登录用户的收货地址动态的加载到这个下拉列表中。从数据库的角度,是一个select查询语句。已经编写了根据用户的uid来查询当前用户的收货地址数据。
2.orderConfirm.html页面中,收货地址数据的展示需要自动进行加载,需要将方法的逻辑放在ready()函数中。

$(document).ready(function () {
	showCartList();
	showAddressList();
});

3.声明和定义showAddressList()方法,方法中发送ajax请求即可。

function showAddressList() {
	//清空tbody标签的数据
	$("#address-list").empty();
	$.ajax({
		url: "/addresses/",
		type: "get",
		dataType: "JSON",
		success: function (json) {
			if(json.state == 200) {
				let list= json.data;
				for (let i = 0; i < list.length; i++) {
					let opt = "<option value='#{aid}'>#{name}&nbsp;&nbsp;&nbsp;#{tag}&nbsp;&nbsp;&nbsp;#{provinceName}#{cityName}#{areaName}#{address}&nbsp;&nbsp;&nbsp;#{phone}</option>";
					opt = opt.replace(/#{aid}/g, list[i].aid);
					opt = opt.replace(/#{name}/g, list[i].name);
					opt = opt.replace(/#{tag}/g, list[i].tag);
					opt = opt.replace(/#{provinceName}/g, list[i].provinceName);
					opt = opt.replace(/#{cityName}/g, list[i].cityName);
					opt = opt.replace(/#{areaName}/g, list[i].areaName);
					opt = opt.replace(/#{address}/g, list[i].address);
					opt = opt.replace(/#{phone}/g, list[i].phone);

					$("#address-list").append(opt);
				}
			}
		},
		error: function (xhr) {
			alert("购物车收货地址加载产生未知的异常" + xhr.status);
		}
	});
}
  • 1
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值