> 技术文档 > 【基于SprintBoot+Mybatis+Mysql】电脑商城项目之加入购物车和显示购物车列表_springboot+mybatis+mysql电脑商城项目实战

【基于SprintBoot+Mybatis+Mysql】电脑商城项目之加入购物车和显示购物车列表_springboot+mybatis+mysql电脑商城项目实战

🧸安清h:个人主页 

   🎥个人专栏:【Spring篇】【计算机网络】【Mybatis篇】

🚦作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。


目录

🚀1.加入购物车-数据创建

🚀2.加入购物车-实体类

🚀3.加入购物车-持久层

✨3.1规划需要执行的SQL语句

✨3.2设计接口和抽象方法

✨3.3 SQL映射

🚀4.加入购物车-业务层

✨4.1规划异常

✨4.2接口和抽象方法的设计

✨4.3实现接口 

🚀5.加入购物车-控制层

✨5.2设计请求

✨5.3处理请求

🚀6.加入购物车-前端页面

🎯1.显示购物车列表- 持久层

✨1.1规划SQL语句

✨1.2构建VO类

✨1.3设计接口和抽象方法

✨1.4配置SQL映射

🎯2.显示购物车列表- 业务层

🎯3.显示购物车列表- 控制层

✨3.1设计请求

✨3.2处理请求 

🎯4.显示购物车列表- 前端页面

🎃1. 增加购物车商品数量-持久层

✨1.1规划需要执行的SQL语句

✨1.2设计接口和抽象方法

✨1.3配置SQL映射 

🎃 2.增加购物车商品数量-业务层

✨2.1规划异常

✨2.2设计接口和抽象方法

✨ 2.3实现方法

🎃 3.增加购物车商品数量-控制层

✨3.1处理异常

✨3.2设计请求

✨3.3处理请求 

🎃 4.增加购物车商品数量-前端页面


🚀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;

num:当用户重复添加商品时,只修改num就可以了,无需再重复添加商品。 

🚀2.加入购物车-实体类

public class Cart extends BaseEntity{ private Integer cid; private Integer uid; private Integer pid; private Long price; private Integer num;。。。。。。}

🚀3.加入购物车-持久层

✨3.1规划需要执行的SQL语句

1.向购物车表中插入数据。

insert into t_cart values(值列表)

2.当当前的商品已经在购物车中存在,则直接更新num的数量即可。

update t_cart set num=? where cid=?

 3.在插入或更新具体执行那个语句,取决于数据库中是否有当前的这个购物车商品的数据,得去查询才能查询。对当前的用户的pid进行查询,加上uid=?,而不是对当前的整张表进行查询。

select * from t_cart where pid=? and uid=?

✨3.2设计接口和抽象方法

创建一个CartMapper接口持久层的文件。

/** * 插入购物车数据 * @param cart 购物车数据 * @return 受影响的行数 * 插入时最好放在一个对象中传递,所以用Cart参数列表 * 插入后在业务层可能调用,需要有返回值判断能否插入成功 */ Integer insert(Cart cart); /** * 更新购物车某件商品的数量 * @param cid 购物数据id * @param num 更新的数量 * @param modifiedUser 修改人 * @param modifiedTime 修改时间 * @return 受影响的行数 * 更新时涉及到修改人和修改时间,除了cid外,还需要知道数量num */ Integer updateNumByCid(Integer cid, Integer num, String modifiedUser, Date modifiedTime); /** * 根据用户的id和商品的id来查询购物车中的数据 * @param uid 用户id * @param pid 商品id */ Cart findByUidAndPid(Integer uid,Integer pid);

✨3.3 SQL映射

1.创建一个CartMapper.xml映射文件,添加以上三个抽象方法的SQL映射。

         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})   update t_cart set num=#{num},modified_user=#{modifiedUser},modified_time=#{modifiedTime} where cid=#{cid}   select * from t_cart where pid=#{pid} and uid=#{uid} 

2.进行测试 

@SpringBootTestpublic class CartMapperTests { @Autowired private CartMapper cartMapper; @Test public void insert(){ Cart cart = new Cart(); cart.setNum(3); cart.setPid(10000002); cart.setUid(6); cartMapper.insert(cart); } @Test public void updateNumByCid(){ cartMapper.updateNumByCid(1,6,\"小明\",new Date()); } @Test public void findByUidAndPid(){ Cart cart = cartMapper.findByUidAndPid(6,10000002); System.err.println(cart); }}

🚀4.加入购物车-业务层

✨4.1规划异常

1.插入数据时可能产生异常:InsertException。

2.更新数据时可能产生异常:UpdateException。

✨4.2接口和抽象方法的设计

分析:

1.首先要进行商品的查询,这里面通过findByUidAndPid方法必须要传递过来的是uid和pid的字段。

2.假设拿到后,就要对原有的数据进行更新,需要传递的字段有:cid,num,username。

 /** * 将商品添加到购物车中 * @param uid 用户id * @param pid 商品id * @param amount 新增数量 * @param username 用户名(修改者) */ void addToCart(Integer uid,Integer pid,Integer amount,String username);

✨4.3实现接口 

1.创建一个CartServiceImpl的实现类。

@Servicepublic class CartServiceImpl implements ICartService {//购物车的业务层依赖于购物车的持久层和商品的持久层 @Autowired private CartMapper cartMapper; @Autowired //购物车中的一些定义的字段实际上是从商品表中分离出来的 private ProductMapper productMapper; @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 cart = new Cart(); //补全数据:首先补全参数传递过来的数据 cart.setPid(pid); cart.setUid(uid); //这里的amount暂且理解为在前端加好,把总数传递过来 cart.setNum(amount); //补全价格:来自于商品中的数据 Product product = productMapper.findById(pid); cart.setPrice(product.getPrice()); //补全四日志 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 cid = result.getCid(); Integer rows = cartMapper.updateNumByCid(cid,num,username,date); if(rows != 1){ throw new UpdateException(\"更新时产生未知的异常\"); } } }}

2. 再创建对应的测试类CartServiceTests。

@SpringBootTestpublic class CartServiceTests { @Autowired private ICartService cartService; @Test public void addToCart(){ cartService.addToCart(6,10000013,2,\"北伐不成功不改名\"); }}

🚀5.加入购物车-控制层

1.没有需要处理的异常。

✨5.2设计请求

请求路径:/carts/add_to_cart

请求方式:POST

请求数据:Integer pid,Integer amount,HttpSession session

响应结果:JsonResult

✨5.3处理请求

1.创建一个CartController类,具体代码如下:

@RequestMapping(\"carts\")@RestControllerpublic class CartController extends BaseController{ @Autowired private ICartService cartService; @RequestMapping(\"add_to_cart\") public JsonResult addToCart(Integer pid, Integer amount, HttpSession session){ cartService.addToCart(getuidFromSession(session),pid,amount,getUsernameFromSession(session)); return new JsonResult(OK); }}

 2.登录后访问:http://localhost:8080/carts/add_to_cart?pid=10000003&amount=1

🚀6.加入购物车-前端页面

在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);}});});

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

  • data:$(\"form表单选择\").serialize()。适合要么就是可以全部选择的,或者手动输入的串的类型。当参数过多并且在同一个字符串中。
  • data:new FormData($(\"form表单选择\")[0])。只适用提交文件,其他形式提交不了。
  • data:\"username=Tom\"。适合参数值固定并且参数值列表有限,可以进行手动拼接。
    let user = \"tom\";data:\"username=\"+user
  • 适用JSON格式提交数据:
    data:{ \"username\":\"tom\", \"age\":18, \"sex\":0}

🎯1.显示购物车列表- 持久层

✨1.1规划SQL语句

分析上图可知,红线框住的图片和商品标题来自于product表,而蓝线框住的应该属于 cart表,单价和数量应该是从购物车中传过来的,再根据两者计算总金额。由于数据来自于两张表中的部分字段,所以要用到关联查询。

#多表查询如果字段不重复则不需要显式声明字段属于哪张表select cid, uid, pid, t_cart.price, t_cart.num, t_product.image, t_product.title, t_product.price as realfrom t_cart left join t_product on t_cart.pid=t_product.idwhere uid=#{uid}order by t_cart.createdTime DESC;

✨1.2构建VO类

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

在com.cy.store下新建一个包VO,在VO包里创建CartVO类。 

//购物车数据的VO类(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 String image; private Long realPrice;......}

✨1.3设计接口和抽象方法

在CartMapper中编写如下代码:

List findVOByUid(Integer uid);

✨1.4配置SQL映射

  select cid,  uid,  pid,  t_cart.price,  t_cart.num,  t_product.image,  t_product.title,  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.createdTime DESC 

单元测试

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

🎯2.显示购物车列表- 业务层

1.先编写业务层的接口方法。

List getVOByUid(Integer uid);

2.在实现类中实现方法。

@Override public List getVOByUid(Integer uid) { List list = cartMapper.findVOByUid(uid); return list; }

🎯3.显示购物车列表- 控制层

✨3.1设计请求

请求路径:/carts/(只要发一个carts就可以把列表返回,不需要carts下的什么)

请求方式:GET

请求数据:HttpSession session

响应结果:JsonResult<List>

✨3.2处理请求 

1.实现请求处理方法的代码编写。

 @RequestMapping({\"/\",\"\"}) public JsonResult<List> getVOByUid(HttpSession session){ List data = cartService.getVOByUid(getuidFromSession(session)); return new JsonResult(OK,data); } 

2.先登录再进行功能测试,访问http://localhost:8080/carts。

🎯4.显示购物车列表- 前端页面

要把cart.html页面通过向Controller层中的getVOByUid方法发送请求就可以返回所有的数据。

1.先注释掉以下代码:

2.用户一打开页面就自动发送请求,请求数据。读取form表单,对它的结构做一个了解,因为要把数据显示在form表单中。

  • action=\"orderConfirm.html\"
  • tbody标签的id=\"cart-list\"属性,自动加载的内容需要体现在tbody中。
  • type=\"button\":结算按钮的submit改成button,后续需要传数据。

3.ready()函数来完成自动的ajax请求的提交和处理。

$(document).ready(function () {showCartList();});//展示购物车列表数据function showCartList() {$(\"#cart-list\").empty();$.ajax({url: \"/carts\",type: \"GET\",dataType: \"JSON\",success: function(json) {let list = json.data;for (var i = 0; i < list.length; i++) {//用户所拿到的是一个list集合,在这个list集合中封装的是cartVO对象,在这里先拿到这个list集合let tr = \'\\n\' +\'\\n\' + //在这里给复选框一个cid值,在往后点击结算的时候会把这个cid值传递给下个页面//把这个数据提交给另一个页面是以参数的形式提交,所以这个表单一定要有内部属性\'\\n\' +\'\\n\' +\'【基于SprintBoot+Mybatis+Mysql】电脑商城项目之加入购物车和显示购物车列表_springboot+mybatis+mysql电脑商城项目实战\\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);}});}

🎃1. 增加购物车商品数量-持久层

✨1.1规划需要执行的SQL语句

1.执行更新t_cart表记录的num的值,无需重复开发。

update t_cart set num=#{num},modified_time={modifiedTime},modified_user=#{modifiedUser} where cid=#{cid}

2.根据cid查询购物车的这条记录是否存在。

select * from t_cart where cid=?

✨1.2设计接口和抽象方法

Cart findByCid(Integer cid);

✨1.3配置SQL映射 

  select * from t_cart where cid=#{cid} 

编写单元测试。

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

🎃 2.增加购物车商品数量-业务层

✨2.1规划异常

1.在更新时会产生更新异常。

2.查询到的数据是否有访问权限。

3.查询的数据不存在,抛出:CartNotFoundException异常。

public class CartNotFoundException extends ServiceException{ public CartNotFoundException() { super(); } public CartNotFoundException(String message) { super(message); } public CartNotFoundException(String message, Throwable cause) { super(message, cause); } public CartNotFoundException(Throwable cause) { super(cause); } protected CartNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); }}

✨2.2设计接口和抽象方法

 /** * 更新用户的购物车数据 * @param cid * @param uid * @param username * @return 增加成功后新的数量 */ Integer addNum(Integer cid,Integer uid,String username);

✨ 2.3实现方法

 @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.1处理异常

else if(e instanceof CartNotFoundException) { result.setState(4007); result.setMessage(\"购物车数据不存在的异常\"); }

✨3.2设计请求

请求路径:/carts/{cid}/num/add

请求方式:POST

请求数据:Integer cid,HttpSession session

响应结果:JsonResult

✨3.3处理请求 

 @RequestMapping(\"{cid}/num/add\") public JsonResult addNum(Integer cid,HttpSession session){ Integer data = cartService.addNum(cid,getuidFromSession(session),getUsernameFromSession(session)); return new JsonResult(OK,data); }

先登录在访问url地址对应的地址。 

🎃 4.增加购物车商品数量-前端页面

1.前面已经在onclick中改过里面的内容,所以无需重复修改了,但是需要重新编写addNum()以确保点击后能够增加数量。

function addNum(cid){$.ajax({url: \"/carts/\"+cid+\"/num/add\",type: \"POST\",dataType: \"JSON\",success: function (json) {if (json.state == 200) {//先拿到数量展示的id,$(\"#goodsCount\"+cid).val(json.data)//由于price的值不是放在val控件上,也不是放在某一个属性上,通过html来拿,//html就是拿到它标签内部的这个东西,如果内部是个串拿到的就是个串//获取某个标签内部的内容:文本、标签//因为刚好这个内容即:singlePrice作为一个子内容放在了开始和结束的中间let price = $(\"#goodsPrice\"+cid).html();let totalPrice = price * json.data;$(\"#goodsCast\"+cid).html(totalPrice);} else {alert(\"增加购物车商品数量失败\")}},error: function (xhr) {alert(\"增加购物车商品数量时产生未知的异常!\"+xhr.message);}});}