购物车模块

数据库创建

image-20230813101249386

实体类创建

com.bang.store.pojo中创建购物车对应的实体类Cart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.bang.store.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 购物车实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Cart extends BasePojo{
Integer cid;
Integer uid;
Integer pid;
Long price;
Integer num;

}

解决实体类tostring无法打印父类属性的问题

资料参考

持久层

规划执行的SQL语句

1.用户在商品详细页点击加入购物车按钮,像后端发送请求,将对应数据插入数据库,本质是insert语句

1
insert into t_cart(uid,pid,price,num,created_user,created_time,modified_user,modified_time) values(?,?,?,?,?,?,?,?);

2.当前商品在数据库中已经存在时,直接更新数据库中属性num的值即可

为什么根据cid来更新?

因为在决定执行插入或者更新操作之前,需要先查询商品在数据库中是否存在,如果存在则执行更新操作,查询即可获取当前记录的cid

1
update t_cart set num=?,modified_user=?,modified_time=? where cid=?

3.查询当前商品在购物车中是否存在

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

接口和抽象方法

创建购物车模块业务层接口CartMapper,在其中定义对应的抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.bang.store.mapper;

import com.bang.store.pojo.Cart;

import java.util.Date;

/**
* 购物车业务层接口
*/
public interface CartMapper {

/**
* 查询某个商品在购物车中是否存在
* @param uid 用户id
* @param pid 商品id
* @return 购物车商品数据,不存在返回null
*/
Cart findByUidPid(Integer uid, Integer pid);


/**
* 享购物车中插入商品
* @param cart 商品数据
* @return 受影响行数
*/
Integer insert(Cart cart);

/**
* 更新购物车商品数量
* @param cid 购物车数据id
* @param num 商品数量
* @param modifiedUser 修改者用户名
* @param modifiedTime 修改操作时间
* @return 受影响的行数
*/
Integer updateNumByCid(Integer cid, Integer num, String modifiedUser, Date modifiedTime);
}

SQL映射文件的配置

resource/static/mapper文件夹下新建映射文件CartMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bang.store.mapper.CartMapper">
<resultMap id="cartPojoMap" type="com.bang.store.pojo.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="findByUidPid" resultMap="cartPojoMap">
select * from t_cart where uid=#{uid} and pid=#{pid};
</select>
</mapper>

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.bang.store.mapper;

import com.bang.store.pojo.Cart;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;
import java.util.Date;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class CartMapperTest {

@Resource
CartMapper cartMapper;
@Test
public void insert(){
Cart cart = new Cart();
cart.setUid(1);
cart.setPid(2);
cart.setNum(5);
cart.setPrice(32L);
cart.setCreatedUser("管理者");
cart.setCreatedTime(new Date());
cart.setModifiedUser("管理者");
cart.setModifiedTime(new Date());

Integer rows = cartMapper.insert(cart);
System.out.println(rows);
}

@Test
public void findByUidPid(){
Cart cart = cartMapper.findByUidPid(1, 2);
System.out.println(cart);
}

@Test
public void updateNumByCid(){
Integer rows = cartMapper.updateNumByCid(1, 15, "管理员", new Date());
System.out.println(rows);
}
}

业务层

规划异常

插入数据时异常,InsertException在此前模块已经定义过

更新数据时异常,UpdateException,在此前模块也已经定义过

接口和抽象方法

编写购物车业务层接口com.bang.store.service.IAddressService,在其中编写对应的抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.bang.store.service;

/**
* 购物车业务层接口
*/
public interface ICartService {

/**
* 将商品添加至购物车
* @param uid 用户id
* @param username 用户姓名
* @param pid 商品id
* @param num 商品数量
*/
void add2Cart(Integer uid,String username,Integer pid,Integer num);
}

抽象方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.bang.store.service.impl;

import com.bang.store.mapper.CartMapper;
import com.bang.store.mapper.ProductMapper;
import com.bang.store.pojo.Cart;
import com.bang.store.pojo.Product;
import com.bang.store.service.ICartService;
import com.bang.store.service.ex.InsertException;
import com.bang.store.service.ex.ProductNotFoundException;
import com.bang.store.service.ex.UpdateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

@Service
public class CartServiceImpl implements ICartService {
@Resource
CartMapper cartMapper;
@Resource
ProductMapper productMapper;
@Override
public void add2Cart(Integer uid, String username, Integer pid, Integer num) {
//查询当前商品记录在数据库中是否存在
Cart result = cartMapper.findByUidPid(uid, pid);
if(result==null){ //商品不存在执行插入操作
Cart cart = new Cart();
//查询商品信息
//Q:为什么这里价格不从前端页面传回数据?
//A:这里可以从前端传递,但是如果功能扩展,需要根据pid查询商品信息,查询商品是否下架或者商品数量是否有货等
Product product = productMapper.findById(pid);
if(product==null){
throw new ProductNotFoundException("商品不存在异常");
}
cart.setUid(uid);
cart.setPid(pid);
cart.setPrice(product.getPrice());
cart.setNum(num);
cart.setCreatedUser(username);
cart.setCreatedTime(new Date());
cart.setModifiedUser(username);
cart.setModifiedTime(new Date());
Integer rows = cartMapper.insert(cart);
if(rows!=1){
throw new InsertException("商品插入未知异常");
}
}else{ //商品存在则执行更新操作
Integer cid = result.getCid();
num+=result.getNum();
Integer rows = cartMapper.updateNumByCid(cid, num, username, new Date());
if(rows!=1){
throw new UpdateException("购物车数据更新发生未知异常");
}
}

}
}

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.bang.store.service;

import com.bang.store.mapper.CartMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class CartServiceTest {

@Autowired
ICartService cartService;

@Test
public void add2Cart(){
Integer uid=1;
String username="admin1";
Integer pid=100000424;
Integer num =20;
cartService.add2Cart(uid,username,pid,num);
}
}

控制层

异常处理

InsertExceptionUpdateExcpetion的异常处理在前面模块中已经编写,业务层无新增异常类型

设计请求

1
2
3
4
request url: /cart/add_to_cart
request method: GET
request params: Integer pid,Integer num,HttpSession session
response data: new JsonResult<Void>

处理请求

编写购物车控制层接口com.bang.store.controller.CartController并继承控制层基类BaseController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.bang.store.controller;

import com.bang.store.service.ICartService;
import com.bang.store.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
@RequestMapping("/cart")
public class CartController extends BaseController{
@Autowired
ICartService cartService;

@RequestMapping("/add_to_cart")
public JsonResult<Void> add2cart(Integer pid, Integer num, HttpSession session){
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
cartService.add2Cart(uid,username,pid,num);
return new JsonResult<>(OK,"商品成功添加到购物车");
}
}

前端页面

在商品详情页界面product.html中,用户点击添加购物车按钮,则向后端发送请求,将对应商品数据存入购物车数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//点击加入一样购物车按钮,向后端发送ajax请求
$("#btn-add-to-cart").click(function (){
addToCart(pid,$("#num").val());
});

function addToCart(pid,num) {
$.ajax({
url: "/cart/add_to_cart"
,type: "GET"
,data: {
"pid": pid
,"num": num
}
,dataType: "JSON"
,success: function (data){
if(data.state == 200){
alert(data.data.message);
}else{
alert("商品添加至购物车失败 "+data.message);
}
}
,error:function (xmh){
alert("商品添加至购物车发生未知错误"+xmh.status);
}
});
}