SpringBoot项目--电脑商城【显示购物车列表】

1.持久层

1.1规划需要执行的SQL语句

这里需要将商品表和购物车表进行连表查询

显示某用户的购物车列表数据的SQL语句大致是

多表查询如果字段不重复则不需要显示的表面表名

select
	cid, #日后勾选购物车商品模块需要用到cid来确定勾选的是购物车表的哪一条数据
	
	uid, #感觉没必要,因为uid可以从session中拿的呀,难道是为
	#了后面提交购物车订单时判断提交的商品的uid和登录的uid是否一致?
	
	pid, #日购提交订单模块需要用到pid来确定购买的是商品表的哪件商
	#品,然后对商品表的该商品的库存,销售热度等信息进行修改
	
	t_cart.price, #两个表都有该字段,需要指定获取的是哪个数据表的
	
	t_cart.num, #两个表都有该字段且含义不同,需要指定获取的是哪个数据表的
	
	title,
	
	t_product.price as realPrice, #为了在购物车列表页展示两个价格的差值
	
	image
	
from t_cart
left join t_product on t_cart.pid = t_product.id #把t_cart作为主表
where
	uid = #{uid}
order by
	t_cart.created_time desc #进行排序使最新加入购物车的在最上面

1.2 VO对象:显示给前端页面的数据【多表操作】

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

在store包下创建一个vo包,在该包下面创建CartVO类,不需要继承BaseController类,那相应的就需要单独实现Serializable接口

/**
 * 不需要继承BaseController类,那相应的就需要单独实现Serializable接口
 * 购物车数据的VO类(Value Object)
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
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;
}

2.在CartMapper接口中添加抽象方法

/**
 * 查询某用户的购物车数据
 * @param uid 用户id
 * @return 该用户的购物车数据的列表
 */
List<CartVO> findVOByUid(Integer uid);

1.3 编写映射

    <select id="findVOByUid" resultType="com.example.mycomputerstore.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>

1.4 单元测试

在CartMapperTests测试类中添加findVOByUid()方法的测试

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

2.业务层

2.1 规划异常

查询不到就返回空,不需要规划异常【查询没有异常】

2.2设计接口和抽象方法及实现

1.在ICartService接口中添加findVOByUid()抽象方法

/**
 * 查询某用户的购物车数据
 * @param uid 用户id
 * @return 该用户的购物车数据的列表
 */
List<CartVO> getVOByUid(Integer uid);

2.在CartServiceImpl类中重写业务接口中的抽象方法

@Override
public List<CartVO> getVOByUid(Integer uid) {
    return cartMapper.findVOByUid(uid);
}

2.3单元测试

该业务层只是调用了持久层的方法并返回,可以不再测试

3.控制层

3.1 处理异常

业务层没有抛出异常,所以这里不需要处理异常

3.2 设计请求

  • /carts/
  • GET
  • HttpSession session
  • JsonResult<List<CartVO>>

3.3 处理请求

在CartController类中编写处理请求的代码。

    /**
     * 根据用户id查询购物车
     * @param session: 为了获取用户的uid
     * @return
     */
    @GetMapping({"/",""})//表示直接输入/cart就可以访问
    public JsonResult<List<CartVO>> getVOByUid(HttpSession session){
        List<CartVO> data = cartService.getVOByUid(getuidFromSession(session));
        return new JsonResult<>(OK,data);
    }

4. 前端页面

1.将cart.html页面的head头标签内引入的cart.js文件注释掉(这个就是文件的功能:点击"+“,”-",“删除”,"全选"等按钮时执行相应的操作)

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

多说一下,form标签的action="orderConfirm.html"属性(规定表单数据提交到哪里)和结算按钮的类型"type=submit"是必不可少的,这样点击"结算"时才能将数据传给"确认订单页"并在"确认订单页"展示选中的商品数据

当然也可以把这两个删掉,然后给结算按钮添加"type=button"然后给该按钮绑定一个点击事件实现页面跳转和数据传递,但是这样太麻烦了

 submit和button的区别

submit和button,二者都以按钮的形式展现,看起来都是按钮,所不同的是type属性和处发响应的事件上,submit会提交表单,button不会提交表单. submit默认为form提交,可以提交表单(form). button则响应用户自定义的事件,如果不指定onclick等事件处理函数,它是不做任何事情.

2.注意点:form表单结构。

  • action="orderConfirm.html"
  • id="cart-list"
  • type="button" value="  结  算  "

3.使用ajax发起请求用户购物车的数据

<script type="text/javascript">
			/*
			* 读取当前页面的加载
			* */
			$(document).ready(function (){
				//展示购物车列表
				showCartList()
			})

			//展示购物车列表
			function showCartList(){
				//清空tbody
				$("#cart-list").empty()
				$.ajax({
					url:"/cart",
					type:"GET",
					dataType:"JSON",
					success: function (e) {
						console.log(e.data)
						//获取数据
						let list = e.data;
						for (let i=0;i<list.length;i++) {
							/*
							*  name="cids" value="#{cid}":为了传到“确认支付”页面做准备
							* ..#{image}collect.png==数据库中的样式【/images/portal/00GuangBo1040A5GBR0731/】
							* 	实际上需要的是【../images/portal/00GuangBo1040A5GBR0731/collect.png】
							*   msg:表示真实价格
							* */
							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" onclick="reduceNum(2)" />\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="+" onclick="addNum(2)" />\n' +
									'</td>\n' +
									'<td><span id="goodsCast#{cid}">#{totalPrice}</span></td>\n' +
									'<td>\n' +
									'<input type="button" onclick="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}",list[i].num)
							//单价
							tr=tr.replace("#{singlePrice}",list[i].price)
							//总价
							tr=tr.replace(/#{totalPrice}/g,list[i].price*list[i].num)

							//将数据加入表中
							$("#cart-list").append(tr);
						}
					},
					error(xhr){
						alert("购物车列表数据加载产生未知的异常"+xhr.status)
					}
				})
			}
		</script>

这tr变量是怎么声明的呢:

先敲下var=‘’;然后在上面的html里面找到tbody下的任意一个tr标签复制在单引号里面,然后删掉制表符.最后对该字符串稍加改动:

1.第18行name=“cids” value="#{cid}"是为"点击结算按钮跳转到确认订单页面"模块做准备。这两个属性都是自己添加的,在tbody复制的tr标签里面没有,这两个属性是为了跳转到"确认订单页"时能够携带该参数(比如传递cids=1)

2.第26οnclick="addNum(#{cid})“是为"在购物车列表增加商品数量"模块做准备。是为了点击”+"后能调用addNum函数并传入对应的cid

3.第22行id="goodsPrice#{cid}"和第25行id="goodsCount#{cid}"和第28行id="goodsCast#{cid}"都是为"在购物车列表增加商品数量"模块做准备。在后端更新完商品数量相应的前端页面也要更新:

根据id="goodsCount#{cid}"获取数量相关的控件后更新其value属性的值(value属性用.val()赋值)
根据id="goodsPrice#{cid}"获取价格相关的控件后拿到其单价
将单价和数量相乘后,根据id="goodsCast#{cid}"获取总价相关的控件并更新其文本值(文本用.html()更新)
4.上面这三条都是和本模块无关的,其余的修改都是和本模块相关的,在tbody复制的tr标签里面都有,比葫芦画瓢就可以了

点击"结算"按钮页面跳转的实现:在cart.html页面点击"结算"后会跳转到"确认订单页"并将表单中的数据作为参数传递给"确认订单页"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值