该系列博客主要记录笔者的开发过程,参考B站系列视频:【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战_哔哩哔哩_bilibili
所用的一些版本信息:
IDEA开发、JDK1.8版本以上、maven3.61版本以上,springboot,DataGrip管理数据库
购物车页面展示如下:
0 前置准备
0.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;
0.2 创建实体类
创建 store\src\main\java\com\cy\store\entity\Cart.java 文件。
public class Cart {
private Integer cid;
private Integer uid;
private Integer pid;
private Long price;
private Integer num;
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Cart cart = (Cart) o;
return Objects.equals(cid, cart.cid) && Objects.equals(uid, cart.uid) && Objects.equals(pid, cart.pid) && Objects.equals(price, cart.price) && Objects.equals(num, cart.num);
}
@Override
public int hashCode() {
return Objects.hash(cid, uid, pid, price, num);
}
}
0.3 功能规划
主要有以下两大功能:
1.在商品详情页添加商品
2.展示购物车列表
1 持久层
1.1 规划SQL语句
1.插入语句 insert
2.当前商品已存在,更新num数量,update
3.插入更新执行前,查询数据库该用户是否有这个商品,select
4.查询该用户购物车所有的商品,以及商品对应的详情
1.2 接口和抽象方法
在语句4查询后的给前端显示的购物车信息使用的是VO对象:
Value Object,值对象。当进行SELECT查询时,结果为多表时,POJO实体类无法接收,构建VO对象去存储查询出来的结果集对应的映射。
创建:store\src\main\java\com\cy\store\vo
package com.cy.store.vo;
import java.io.Serializable;
import java.util.Objects;
/**购物车的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;
//...... getter ,setter, equals, hashCode
}
创建 store\src\main\java\com\cy\store\mapper\CartMapper.java 文件
package com.cy.store.mapper;
import com.cy.store.entity.Cart;
import java.util.Date;
public interface CartMapper {
/**
* 插入数据
* @param cart
* @return
*/
Integer insert(Cart cart);
/**
* 根据cid修改剩余数量num
* @param cid
* @param num
* @param modified_user
* @param modified_time
* @return
*/
Integer updateByCid(Integer cid, Integer num, String modified_user, Date modified_time);
/**
* 根据用户和商品id查询购物车
* @param uid
* @param pid
* @return
*/
Cart findByUidAndPid(Integer uid, Integer pid);
/**
* 展示购物车数据查询
* @param uid
* @return
*/
List<CartVO> findByUid(Integer uid);
}
1.3 SQL映射
创建 store\src\main\resources\mapper\CartMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace需要映射到java中的接口,指定路径-->
<mapper namespace="com.cy.store.mapper.CartMapper">
<resultMap id="CartEntityMap" type="com.cy.store.entity.Cart">
<id column="cid" property="cid"/>
<result column="created_user" property="createdUser"/>
<result column="created_time" property="createdTime"/>
<result column="modified_user" property="modifiedUser"/>
<result column="modified_time" property="modifiedTime"/>
</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>
<select id="findByUid" resultMap="com.cy.store.vo.CartVO">
SELECT
cid,
uid,
pid,
t_cart.price,
t_cart.num,
t_product.title,
t_product.price AS realPrice,
t_product.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>
</mapper>
1.4 单元测试
2 业务层
2.1 规划异常
1.插入时异常
2.更新数据异常
3.查询无异常
2.2 接口与抽象方法
新建:store\src\main\java\com\cy\store\service\ICartService.java
package com.cy.store.service;
import com.cy.store.vo.CartVO;
import java.util.List;
/** 购物车的业务层 */
public interface ICartService {
/**
* 将商品添加到购物车中
* @param uid 用户id
* @param pid 商品id
* @param num
* @param username
*/
void addToCar(Integer uid, Integer pid, Integer num, String username);
/**
* 查询购物车显示数据
* @param uid
* @return
*/
List<CartVO> getVOByUid(Integer uid);
}
2.3 实现抽象方法
新建 store\src\main\java\com\cy\store\service\impl\CartServiceImpl.java
package com.cy.store.service.impl;
import com.cy.store.entity.Cart;
import com.cy.store.entity.Product;
import com.cy.store.mapper.CartMapper;
import com.cy.store.mapper.ProductMapper;
import com.cy.store.service.ICartService;
import com.cy.store.service.IProductService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.ProductNotFoundException;
import com.cy.store.service.ex.UpdateException;
import com.cy.store.vo.CartVO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/** 处理商品数据的业务层实现类 */
@Service
public class CartServiceImpl implements ICartService {
@Resource
private CartMapper cartMapper;
@Resource
private ProductMapper productMapper;
@Override
public void addToCar(Integer uid, Integer pid, Integer num, String username) {
// 查询当前添加的购物车是否在表中共已存在
Cart result = cartMapper.findByUidAndPid(uid, pid);
Date date = new Date();
if(result == null){
//商品没有添加过,insert
Cart cart = new Cart();
//补全数据
cart.setUid(uid);
cart.setPid(pid);
cart.setNum(num);
//价格 来自商品数据
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{
//当前商品在购物车中已经存在,update
Integer reNum = result.getNum()+num;
Integer rows = cartMapper.updateNumByCid(result.getCid(), reNum, username, new Date());
if(rows!=1){
throw new UpdateException("更新时产生未知异常");
}
}
}
@Override
public List<CartVO> getVOByUid(Integer uid) {
return cartMapper.findVOByUid(uid);
}
}
3 控制层
3.1 处理异常
无新异常梳理
3.2 设计请求
添加购物车
URL:/carts/add_to_cart
请求方式:GET
请求参数:pid, num, session
返回值:JsonResult<Void>
查询购物车显示数据
URL:/carts/
请求方式:GET
请求参数:session
返回值:JsonResult<List<CartVO>>
3.2 处理请求
新建: store\src\main\java\com\cy\store\controller\CartController.java
package com.cy.store.controller;
import com.cy.store.entity.Address;
import com.cy.store.service.ICartService;
import com.cy.store.util.JsonResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.List;
//@Controller
@RestController //该注解等于@Controller + 方法上的@ResponseBody
@RequestMapping("carts")
public class CartController extends BaseController{
@Resource
private ICartService cartService;
@RequestMapping({"add_to_cart"})
public JsonResult<List<Address>> addToCart(Integer pid, Integer num, HttpSession session){
cartService.addToCar(getuidFromSession(session), pid, num, getusernameFromSession(session));
return new JsonResult<>(OK);
}
}
4 前端页面
在 store\src\main\resources\static\web\product.html 添加请求
$("#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("增加失败!" + json.message);
}
},
error: function(xhr) {
alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
location.href = "login.html";
}
});
});
在store\src\main\resources\static\web\cart.html中
<!--页脚结束-->
<script type="text/javascript">
$(document).ready(function() {
showCartList();
});
function showCartList() {
$("#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>'
+ '<td>'
+ '<input name="cids" value="#{cid}" type="checkbox" class="ckitem" />'
+ '</td>'
+ '<td><img src="..#{image}collect.png" class="img-responsive" /></td>'
+ '<td>#{title}#{msg}</td>'
+ '<td>¥<span id="price-#{cid}">#{realPrice}</span></td>'
+ '<td>'
+ '<input type="button" value="-" class="num-btn" onclick="reduceNum(1)" />'
+ '<input id="num-#{cid}" type="text" size="2" readonly="readonly" class="num-text" value="#{num}">'
+ '<input class="num-btn" type="button" value="+" onclick="addNum(#{cid})" />'
+ '</td>'
+ '<td>¥<span id="total-price-#{cid}">#{totalPrice}</span></td>'
+ '<td>'
+ '<input type="button" onclick="delCartItem(this)" class="cart-del btn btn-default btn-xs" value="删除" />'
+ '</td>'
+ '</tr>';
tr = tr.replace(/#{cid}/g, list[i].cid);
tr = tr.replace(/#{title}/g, list[i].title);
tr = tr.replace(/#{image}/g, list[i].image);
tr = tr.replace(/#{realPrice}/g, list[i].realPrice);
tr = tr.replace(/#{num}/g, list[i].num);
tr = tr.replace(/#{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);
}
}
});
}
function addNum(cid) {
$.ajax({
url: "/carts/" + cid + "/num/add",
type: "POST",
dataType: "JSON",
success: function(json) {
if (json.state == 200) {
// showCartList();
$("#num-" + cid).val(json.data);
let price = $("#price-" + cid).html();
let totalPrice = price * json.data;
$("#total-price-" + cid).html(totalPrice);
} else {
alert("增加商品数量失败!" + json.message);
}
},
error: function(xhr) {
alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
location.href = "login.html";
}
});
}
/*
$(function() {
//返回链接
$(".link-account").click(function() {
location.href = "orderConfirm.html";
});
});
*/
</script>