Project(15)——购物车 - 向购物车加入数据
64、购物车 - 加入购物车 - 创建数据表
CREATE TABLE t_cart(
cid INT AUTO_INCREMENT COMMENT '购物车数据id',
uid INT NOT NULL COMMENT '用户id',
gid BIGINT(20) NOT NULL COMMENT '商品id',
num INT NOT NULL COMMENT '商品数量',
created_user VARCHAR(20) COMMENT '创建人',
created_time DATETIME COMMENT '创建时间',
modified_user VARCHAR(20) COMMENT '修改人',
modified_time DATETIME COMMENT '修改时间',
PRIMARY KEY (cid)
)DEFAULT CHARSET=UTF8;
65、购物车 - 加入购物车 - 创建实体类
创建cn.tedu.store.entity.Cart
实体类,继承自BaseEntity
。
66、购物车 - 加入购物车 - 持久层
将商品添加到购物车,执行的sql语句大致是:
INSERT INTO t_cart(
uid, gid, num, created_user,
created_time, modified_user, modified_time
) VALUES(
#{uid}, #{gid}, #{num}, #{createdUser},
#{createdTime}, #{modifiedUser}, #{modifiedTime}
)
需要注意的是,并不是每次点击“添加购物车”都会产生新数据,例如:7 号用户已经添加了 1 号商品,数量为 2:
uid gid num
7 1 2
此时,如果用户再次点击 1 号商品的“加入购物车”,添加一个到购物车中,这时,应该只修改原有的数量数据,而不添加新的数据:
uid gid num
7 1 3
所以,加入购物车功能还可能执行的sql语句:
UPDATE
t_cart
SET
num=?, modified_user=?, modified_time=?
WHERE
cid=?
用户每次点击“加入购物车”时,到底执行INSERT
操作还是UPDATE
操作,取决于该用户的购物车中有没有该商品
。实现该判断的sql查询语句大致是:
SELECT
*
FROM
t_cart
WHERE
uid=? AND gid=?
执行以上查询时,如果查询到有效结果,则表示“该用户的购物车中已有该商品”,反之,则表示“该用户的购物车中没有该商品”。如果查询到有效结果,后续将执行UPDATE
操作,即:更新购物车中商品的数量,则需要将原数量读出来,用于结合用户此次提交的增量,计算新的数量,并且,还要读出这条数据的 id,便于执行UPDATE
操作,则以上查询应该调整为:
SELECT
cid, num
FROM
t_cart
WHERE
uid=? AND gid=?
分析完成,创建cn.tedu.store.mapper.CartMapper
持久层接口,并添加以上 3 个功能对应的抽象方法:
/**
* 处理购物车数据的持久层接口
* @author DELL
*
*/
public interface CartMapper {
/**
* 插入一条新的购物车数据
* @param cart
* @return
*/
Integer insert(Cart cart);
/**
* 更新商品数据
* @param cid 购物车数据 cid
* @param num 商品数量
* @param modifiedUser 修改人
* @param modifiedTime 修改时间
* @return
*/
Integer updateNum(
@Param("cid") Integer cid,
@Param("num") Integer num,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime") Date modifiedTime);
/**
* 根据 uid 和 gid 查询购物车数据
* @param uid 用户 uid
* @param gid 商品 gid
* @return 商品数据
*/
Cart findByUidAndGid(
@Param("uid") Integer uid,
@Param("gid") Long gid);
}
复制得到CartMapper.xml
配置文件,修改namespace
属性的值,并配置以上 3 个抽象方法的映射:
<?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:xml文件对应哪个接口 -->
<mapper namespace="cn.tedu.store.mapper.CartMapper">
<!-- 插入一条新的购物车数据 -->
<!-- Integer insert(Cart cart) -->
<insert id="insert" useGeneratedKeys="true" keyProperty="cid">
INSERT INTO t_cart(
uid, gid, num, created_user,
created_time, modified_user, modified_time
) VALUES (
#{uid}, #{gid}, #{num}, #{createdUser},
#{createdTime}, #{modifiedUser}, #{modifiedTime}
)
</insert>
<!-- 更新商品数据 -->
<!-- Integer updateNum(
@Param("cid") Integer cid,
@Param("num") Integer num,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime") Date modifiedTime) -->
<update id="updateNum">
UPDATE
t_cart
SET
num=#{num}, modified_user=#{modifiedUser}, modified_time=#{modifiedTime}
WHERE
cid=#{cid}
</update>
<!-- 根据 uid 和 gid 查询购物车数据 -->
<!-- Cart findByUidAndGid(
@Param("uid") Integer uid,
@Param("gid") Long gid) -->
<select id="findByUidAndGid" resultType="cn.tedu.store.entity.Cart">
SELECT
cid, num
FROM
t_cart
WHERE
uid=#{uid} AND gid=#{gid}
</select>
</mapper>
在src/test/java
下创建cn.tedu.store.mapper.CartMapperTests
测试类,编写并执行单元测试:
/**
* 购物车数据持久层测试类
* @author DELL
*
*/
@SpringBootTest
public class CartMapperTests {
@Autowired
private CartMapper cartMapper;
/**
* 测试查询热销列表
*/
@Test
public void testInsert() {
Cart cart = new Cart();
cart.setGid(10000042L);
cart.setNum(1);
cart.setUid(7);
cart.setCreatedUser("酒厂管理员");
Date now = new Date();
cart.setCreatedTime(now);
cart.setModifiedUser("酒厂管理员");
cart.setModifiedTime(now);
cartMapper.insert(cart);
System.err.println("End!");
}
/**
* 测试根据 uid 和 gid 查询购物车数据
*/
@Test
public void testFindByUidAndGid() {
Integer uid = 7;
Long gid = 10000017L;
Cart cart = cartMapper.findByUidAndGid(uid, gid);
System.err.println(cart);
}
/**
* 测试更新商品数据
*/
@Test
public void testUpdateNum() {
Integer cid = 1;
Integer num = 3;
String modifiedUser = "Gin";
Date now = new Date();
Date modifiedTime = now;
cartMapper.updateNum(cid, num, modifiedUser, modifiedTime);
System.err.println("End!");
}
}
67、购物车 - 加入购物车 - 业务层
此次业务层将调用持久层开发的三个方法,其中,查询的方法不会抛异常,因为无论是否查询到数据,此操作都是正确的;而插入数据和更新数据有可能抛出InsertException
和UpdateException
异常。
创建cn.tedu.store.service.ICartService
业务层接口,并添加抽象方法:
/**
* 处理购物车数据的业务层接口
* @author DELL
*
*/
public interface ICartService {
/**
* 向购物车中添加数据
* @param cart
*/
void addToCart(Cart cart, Integer uid, String username) throws InsertException, UpdateException;
}
创建cn.tedu.store.service.impl.CartServiceImpl
业务层实现类,实现以上接口,添加@Service
注解,在类中声明@Autowired private CartMapper cartMapper
持久层对象:
私有化实现持久层中的 3 个抽象方法:
重写接口中的抽象方法:
/**
* 处理购物车数据的业务层实现类
* @author DELL
*
*/
@Service
public class CartServiceImpl implements ICartService {
@Autowired
private CartMapper cartMapper;
/**
* 向购物车中添加商品数据
*/
@Override
public void addToCart(Cart cart, Integer uid, String username) {
// 根据 cart 获取的 gid 和参数 uid 进行数据查询
// 判断查询结果是否为 null
Long gid = cart.getGid();
Cart result = findByUidAndGid(uid, gid);
// 是:
// -- 直接插入数据
// -- 基于参数 uid 向参数 cart 中封装 uid
// -- 基于参数 username 向参数 cart 中封装 createdUser、modifiedUser
// -- 向参数 cart 中封装 createdTime、modifiedTime
// -- 执行插入数据
if(result == null) {
cart.setUid(uid);
cart.setCreatedUser(username);
cart.setModifiedUser(username);
Date now = new Date();
cart.setCreatedTime(now);
cart.setModifiedTime(now);
Integer rows = insert(cart);
if(rows != 1) {
throw new InsertException("向购物车添加数据失败!出现未知错误,请联系系统管理员!");
}
}else {
// 否:
// -- 执行修改数量
// -- 从查询结果中获取 cid
// -- 从查询结果中获取商品原数量 num
// -- 将以上获取的原数量 num 与参数 cart 中的数量相加,得到新数量
// -- 执行修改数量
Integer cid = result.getCid();
Integer num = result.getNum();
num = num + cart.getNum();
Date now = new Date();
Integer rows = updateNum(cid, num, username, now);
if(rows != 1) {
throw new UpdateException("向购物车添加数据失败!出现未知错误,请联系系统管理员!");
}
}
}
// 私有化实现持久层中的 3 个抽象方法
/**
* 插入一条新的购物车数据
* @param cart
* @return
*/
private Integer insert(Cart cart) {
return cartMapper.insert(cart);
}
/**
* 更新商品数据
* @param cid 购物车数据 cid
* @param num 商品数量
* @param modifiedUser 修改人
* @param modifiedTime 修改时间
* @return
*/
private Integer updateNum(
@Param("cid") Integer cid,
@Param("num") Integer num,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime") Date modifiedTime) {
return cartMapper.updateNum(cid, num, modifiedUser, modifiedTime);
}
/**
* 根据 uid 和 gid 查询购物车数据
* @param uid 用户 uid
* @param gid 商品 gid
* @return 商品数据
*/
private Cart findByUidAndGid(
@Param("uid") Integer uid,
@Param("gid") Long gid) {
return cartMapper.findByUidAndGid(uid, gid);
}
}
在src/test/java
中创建cn.tedu.store.service.CartServiceTests
,编写并执行单元测试:
/**
* 购物车数据业务层测试类
* @author DELL
*
*/
@SpringBootTest
public class CartServiceTests {
@Autowired
private ICartService service;
/**
* 向购物车中添加数据
*/
@Test
public void testAddToCart() {
try {
Cart cart = new Cart();
Integer uid = 7;
cart.setGid(10000011L);
cart.setNum(2);
String username = "Vodka";
service.addToCart(cart, uid, username);
System.err.println("End!");
}catch(ServiceException e) {
System.err.println(e.getClass().getName());
System.out.println(e.getMessage());
}
}
}
68、购物车 - 加入购物车 - 控制器层
此次业务层并没有抛出新的异常,则无需处理异常。
新建cn.tedu.store.controller.CartController
控制器类,继承自BaseController
,添加@RestController
和@RequestMapping(“carts”)
注解,并在类中声明@Autowired private CartMapper cartMapper
业务层对象:
请求路径:/carts/add_to_cart
请求参数:Cart cart, HttpSession session
请求类型:post
响应数据:JsonResult<Void>
然后,在控制器类中添加处理请求的方法:
/**
* 购物车信息的控制器类
* @author DELL
*
*/
@RestController
@RequestMapping("carts")
public class CartController extends BaseController {
@Autowired
private ICartService service;
/**
* 像购物车中添加数据
* @param cart 购物车商品数据
* @param session 用于获取 uid、usernam
* @return
*/
@RequestMapping("add_to_cart")
public JsonResult<Void> addToCart(Cart cart, HttpSession session){
// 根据 session 获取 uid、username
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
// 执行向购物车插入数据操作
service.addToCart(cart, uid, username);
// 返回响应结果
return new JsonResult<Void>(SUCCESS);
}
}
完成后,先登录,在地址栏输入http://localhost:8080/carts/add_to_cart?gid=10000011&num=2
进行测试。
69、购物车 - 加入购物车 - 前端页面
删除 product.js
文件中的以下代码: