文章目录静态资源及sql文件分享
链接:https://pan.baidu.com/s/1X-yjmQcPD3PqS21x0HplNA?pwd=23gr
提取码:23gr
- 显示购物车列表
- 1.显示购物车列表-持久层
- 1.1规划需要执行的SQL语句
- 1.2设计接口和抽象方法
- 1.3编写映射
- 1.4单元测试
- 2.显示购物车列表-业务层
- 2.1 规划异常
- 2.2设计接口和抽象方法及实现
- 2.3单元测试
- 3.显示购物车列表-控制层
- 3.1 处理异常
- 3.2 设计请求
- 3.3 处理请求
- 4.显示购物车列表-前端页面
- 增加商品数量
- 1.增加购物车商品数量-持久层
- 1.1规划需要执行的SQL语句
- 1.2设计接口和抽象方法
- 1.3编写映射
- 1.4单元测试
- 2.增加购物车商品数量-业务层
- 2.1规划异常
- 2.2设计接口和抽象方法及实现
- 2.3单元测试
- 3.增加购物车商品数量-控制层
- 3.1处理异常
- 3.2设计请求
- 3.3处理请求
- 4.增加购物车商品数量-前端页面
这里需要将商品表和购物车表进行连表查询
显示某用户的购物车列表数据的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全称Value Object,值对象。当进行select查询时,查询的结果属于多张表中的内容,此时发现结果集不能直接使用某个POJO实体类来接收,因为POJO实体类不能包含多表查询出来的信息,解决方式是:重新去构建一个新的对象,这个对象用于存储所查询出来的结果集对应的映射,所以把这个对象称之为值对象.
在store包下创建一个vo包,在该包下面创建CartVO类,不需要继承BaseController类,那相应的就需要单独实现Serializable接口
/** 购物车数据的Value Object类 */
public class CartVO implements Serializable {
private Integer cid;
private Integer uid;
private Integer pid;
private Long price;
private Integer num;
private String title;
private Long realPrice;
private String image;
/**
* get,set
* equals和hashCode
* toString
*/
}
2.在CartMapper接口中添加抽象方法
/**
* 查询某用户的购物车数据
* @param uid 用户id
* @return 该用户的购物车数据的列表
*/
List<CartVO> findVOByUid(Integer uid);
1.3编写映射
1.在CartMapper.xml文件中添加findVOByUid()方法的映射
<select id="findVOByUid" resultType="com.cy.store.vo.CartVO">
select
cid,
uid,
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
where
uid = #{uid}
order by
t_cart.created_time desc
select>
1.4单元测试
在CartMapperTests测试类中添加findVOByUid()方法的测试
@Test
public void findVOByUid() {
List<CartVO> list = cartMapper.findVOByUid(11);
System.out.println(list);
}
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
在CartController类中编写处理请求的代码。
@RequestMapping({"", "/"})
public JsonResult<List<CartVO>> getVOByUid(HttpSession session) {
List<CartVO> data = cartService.getVOByUid(getUidFromSession(session));
return new JsonResult<List<CartVO>>(OK, data);
}
启动服务,登录后在地址栏输入http://localhost:8080/carts进行测试
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"然后给该按钮绑定一个点击事件实现页面跳转和数据传递,但是这样太麻烦了
2.在cart.html页面body标签内的script标签中编写展示购物车列表的代码
<script type="text/javascript">
$(document).ready(function() {
showCartList();
});
//展示购物车列表数据
function showCartList() {
$("#cart-list").empty();
$.ajax({
url: "/carts",
type: "GET",
dataType: "JSON",
success: function(json) {
var list = json.data;
for (var i = 0; i < list.length; i++) {
var tr = '\n' +
'\n' +
'\n' +
' \n' +
' \n' +
'#{title}#{msg} \n' +
'¥#{singlePrice} \n' +
'\n' +
'\n' +
'\n' +
'\n' +
' \n' +
'#{totalPrice} \n' +
'\n' +
'\n' +
' \n' +
' ';
tr = tr.replaceAll(/#{cid}/g, list[i].cid);
tr = tr.replaceAll(/#{image}/g, list[i].image);
tr = tr.replaceAll(/#{title}/g, list[i].title);
tr = tr.replaceAll(/#{singlePrice}/g, list[i].realPrice);
tr = tr.replaceAll(/#{num}/g, list[i].num);
tr = tr.replaceAll(/#{totalPrice}/g, list[i].realPrice * list[i].num);
if (list[i].realPrice < list[i].price) {
tr = tr.replace(/#{msg}/g, "比加入时降价" + (list[i].price - list[i].realPrice) + "元");
} else {
tr = tr.replace(/#{msg}/g, "");
}
$("#cart-list").append(tr);
}
},
error: function (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页面点击"结算"后会跳转到"确认订单页"并将表单中的数据作为参数传递给"确认订单页"
增加商品数量1.增加购物车商品数量-持久层 1.1规划需要执行的SQL语句购物车详情页点击"+“”-"修改商品数量时必须和数据库进行交互,因为这是即使展示给用户的,不能说用户看到的数量是5,结果数据库的购物车表中的数量是4吧?
但是在商品详情页点击"+“”-“修改商品数量时可以不用和数据库进行交互而是等到用户点击"加入购物车"后再进行交互,因为在用户点击"加入购物车"之前并不需要将商品数量更新到购物车表,可以去看看这个项目的商品详情页,那里点击”+“”-“修改商品数量时就是js实现的,并没有和数据库交互.(如果加一个模块:商品详情页点击”+“”-"时要知道库存够不够用户选择的这个数量,此时就需要和数据库交互了)
1.更新该商品的数量.此SQL语句无需重复开发
2.首先进行查询需要 *** 作的购物车数据信息
SELECT * FROM t_cart WHERE cid=?
1.2设计接口和抽象方法
在CartMapper接口中添加抽象方法
Cart findByCid(Integer cid);
1.3编写映射
在CartMapper文件中添加findByCid(Integer cid)方法的映射
<select id="findByCid" resultMap="CartEntityMap">
select * from t_cart where cid=#{cid}
select>
1.4单元测试
在CartMapperTests测试类中添加findByCid()测试方法
@Test
public void findByCid() {
System.out.println(cartMapper.findByCid(1));
}
2.增加购物车商品数量-业务层
2.1规划异常
- 在更新时产生UpdateException未知异常,此异常类无需再次创建
- 可能该购物车列表数据归属不是登录的用户,抛AccessDeniedException异常,此异常类无需再次创建
- 要查询的数据不存在.抛出CartNotFoundException异常,创建该异常类并使其继承ServiceException
/** 购物车数据不存在的异常 */
public class CartNotFoundException extends ServiceException {
/**重写ServiceException的所有构造方法*/
}
2.2设计接口和抽象方法及实现
在业务层ICartService接口中添加addNum()抽象方法
1.先判断需要哪些参数,该抽象方法的实现依赖于CartMapper接口的两个方法:
updateNumByCid方法.参数是cid,num,String modifiedUser,Date modifiedTime
findByCid方法.参数是cid
在业务层中从购物车表查询到该商品的数量,然后再和前端传过来的增加的数量进行求和得到num
所以该方法的参数是cid,uid,username
2.判断一下该方法的返回值:
- 该方法返回值void.这样的话就需要在前端页面加location.href使该页面自己跳转到自己,实现刷新页面(不建议,每次都加载整个页面,数据量太大了)
- 返回值是Integer类型.这样的话就把数据库中更新后的数量层层传给前端,前端接收后填充到控件中就可以了
/**
* 增加用户的购物车中某商品的数量
* @param cid
* @param uid
* @param username
* @return 增加成功后新的数量
*/
Integer addNum(Integer cid,Integer uid, String username);
3.在CartServiceImpl类中实现接口中的抽象方法
@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;
}
2.3单元测试
就接收个参数,然后业务层将其加一后返回,不需要再测了
3.增加购物车商品数量-控制层 3.1处理异常在BaseController类中添加CartNotFoundException异常类的统一管理
else if (e instanceof CartNotFoundException) {
result.setState(4007);
result.setMessage("购物车表不存在该商品的异常");
}
3.2设计请求
- /carts/{cid}/num/add
- post
- @PathVariable(“cid”) Integer cid, HttpSession session
- JsonResult
在CartController类中添加处理请求的addNum()方法
@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<Integer>(OK, data);
}
启动服务,登录后在地址栏输入http://localhost:8080/carts/1/num/add进行验证
4.增加购物车商品数量-前端页面1.首先确定在showCartList()函数中动态拼接的增加购物车按钮是绑定了addNum()事件,如果已经添加无需重复添加
<input class="num-btn" type="button" value="+" onclick="addNum(#{cid})" />
2.在script标签中定义addNum()函数并编写增加购物车数量的逻辑代码
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);//字符串+整数cid后结果为字符串
//更新该商品总价
/*
html()方法:
不传参:是获取某个标签内部的内容(文本或标签)
传参:将参数放到标签里面替换掉该标签原有内容
* */
var price = $("#goodsPrice"+cid).html();
var totalPrice = price * json.data;
//将商品总价更新到控件中
$("#goodsCast"+cid).html(totalPrice);
} else {
alert("增加购物车商品数量失败"+json.message);
}
},
error: function (xhr) {
alert("增加购物车商品数量时产生未知的异常!"+xhr.message);
}
});
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)