Skip to content

Commit 07bce2a

Browse files
committed
订单与商品之间多对多实现
测试路线文档 部分文档注释
1 parent 7d0172a commit 07bce2a

12 files changed

Lines changed: 194 additions & 38 deletions

File tree

docs/cors-fetch-demo.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ <h1>跨域请求示例🌵🌵🌵</h1>
3434
if (data.code === 200 && data.data?.accessToken) {
3535
const token = data.data.accessToken;
3636
localStorage.setItem('token', token);
37-
document.getElementById('result').textContent = `✅ 登录成功!`;
37+
//localStorage是浏览器的本地存储(永久存储,除非手动删除),存进去后刷新页面重启浏览器都还在
38+
document.getElementById('result').textContent = `✅ 登录成功!token已存储到本地`;
3839
} else {
3940
document.getElementById('result').textContent = `❌ 登录失败:${data.message || '未知错误'}`;
4041
}
@@ -56,6 +57,7 @@ <h1>跨域请求示例🌵🌵🌵</h1>
5657
credentials: 'include',
5758
headers: {
5859
'Access-Token': token // 和拦截器/跨域配置一致
60+
// 手动把Token拼到请求头里
5961
}
6062
});
6163

docs/schema.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ CREATE TABLE `order_product` (
5050
`order_id` int NOT NULL,
5151
`product_id` int NOT NULL,
5252
PRIMARY KEY (`order_id`,`product_id`),
53+
-- 复合主键索引的 “最左匹配” 已覆盖order_id的所有查询,重复建索引无意义
5354
KEY `fk_order_product_product` (`product_id`),
55+
-- 创建「索引」的简写(等价于 INDEX)
56+
-- fk_order_product_product:是索引的自定义名称(命名规则:fk_表名_关联表名_字段名,便于识别)
57+
-- (product_id):表示索引作用在 order_product 表的 product_id 字段上
5458
CONSTRAINT `fk_order_product_order` FOREIGN KEY (`order_id`) REFERENCES `order` (`id`),
5559
CONSTRAINT `fk_order_product_product` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`)
5660
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单商品中间表(多对多关联)';

docs/test..md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
| 测试阶段 | 模块 | 测试接口 | 请求方式 | 前置条件 | 核心测试点 | 异常场景测试 |
2+
|------|------------|---------------------------------------------|--------|------------------|-------------------------------------|----------------------------------------|
3+
| 第一步 | 用户管理 | `/api/user/add` | POST || 1. 返回成功提示;2. 数据库新增用户记录 | 传空 name/phone、重复手机号 |
4+
| | | `/api/user/findById/{id}` | GET | 已新增用户 | 返回用户信息与新增一致 | 传不存在的 ID、ID≤0 |
5+
| | | `/api/user/findByPhone/{phone}` | GET | 已新增用户 | 返回对应手机号的用户信息 | 传不存在的手机号 |
6+
| | | `/api/user/findAll` | GET | 已新增至少 1 个用户 | 返回列表包含所有新增用户 | 无用户时返回空列表 |
7+
| | | `/api/user/update` | PUT | 已新增用户 | 1. 返回成功提示;2. 查询用户信息已更新 | 传不存在的用户 ID、更新字段为空 |
8+
| | | `/api/user/delete/{id}` | DELETE | 已新增用户 | 1. 返回成功提示;2. 查询列表无该用户 | 传不存在的 ID、ID≤0 |
9+
| | | `/api/user/deleteUserAll` | DELETE | 测试环境(最后测) | 查询列表为空 | 无(仅验证数据清空) |
10+
| 第二步 | 商品管理 | `/api/product/add` | POST || 1. 返回成功提示;2. 数据库新增商品记录 | 传空 name、price≤0 |
11+
| | | `/api/product/findById/{id}` | GET | 已新增商品 | 返回商品信息与新增一致 | 传不存在的 ID、ID≤0 |
12+
| | | `/api/product/findByName/{name}` | GET | 已新增商品 | 返回对应名称的商品信息(支持模糊查询则验证模糊匹配) | 传不存在的商品名 |
13+
| | | `/api/product/findAll` | GET | 已新增至少 1 个商品 | 返回列表包含所有新增商品 | 无商品时返回空列表 |
14+
| | | `/api/product/update` | PUT | 已新增商品 | 1. 返回成功提示;2. 查询商品信息已更新 | 传不存在的商品 ID、更新字段为空 |
15+
| | | `/api/product/deleteById/{id}` | DELETE | 已新增商品 | 1. 返回成功提示;2. 查询列表无该商品 | 传不存在的 ID、ID≤0 |
16+
| | | `/api/product/deleteAll` | DELETE | 测试环境(最后测) | 查询列表为空 | 无(仅验证数据清空) |
17+
| 第三步 | 订单基础 | `/api/order/add` | POST | 已新增用户(获取 userId) | 1. 返回成功提示;2. 数据库新增订单记录(userId 关联正确) | 传不存在的 userId、空 orderNo |
18+
| | | `/api/order/findAll` | GET | 已新增至少 1 个订单 | 返回列表包含所有新增订单 | 无订单时返回空列表 |
19+
| | | `/api/order/findUserWithOrders/{id}` | GET | 已新增用户 + 该用户的订单 | 返回用户信息 + 关联的订单列表(数量 / 内容匹配) | 传不存在的用户 ID、无订单的用户 ID |
20+
| 第四步 | 订单 - 商品多对多 | `/api/order/{orderId}/products/{productId}` | POST | 已新增订单 + 商品 | 1. 返回成功提示;2. 中间表 order_product 新增记录 | 传不存在的 orderId/productId、重复添加同一商品 |
21+
| | | `/api/order/{orderId}/products` | GET | 订单已关联商品 | 返回订单信息 + 关联的商品列表(数量 / 内容匹配) | 传不存在的 orderId、无商品的订单 ID |
22+
| | | `/api/order/{orderId}/products/{productId}` | DELETE | 订单已关联该商品 | 1. 返回成功提示;2. 中间表删除对应记录 | 传不存在的 orderId/productId、移除未关联的商品 |
23+
| | | `/api/product/{productId}/orders` | GET | 商品已被订单关联 | 返回商品信息 + 关联的订单列表(数量 / 内容匹配) | 传不存在的 productId、无订单的商品 ID |
24+
| 第五步 | 全局异常 | 所有接口 | 对应方式 || - | 1. 传非数字 ID;2. 接口路径错误;3. Token 失效(若有鉴权) |
25+
| 第六步 | 批量 / 危险接口 | `/api/order/deleteAll` | DELETE | 测试环境(最后测) | 查询订单列表为空 ||

drawbluecup-common/src/main/java/com/drawbluecup/entity/Order.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ public class Order {
1818
private Integer id;//主键自增
1919
private String orderNo;//订单编号.业务展示
2020
private Integer userId;//外键,与主表主键关联
21-
22-
//关联的用户对象(一对多中"多"的一方持有"一"的引用)
23-
// 可选:直接关联用户对象(方便通过订单获取用户信息,如订单属于哪个用户)
2421
private User user;
2522
private LocalDateTime createTime;
2623

drawbluecup-common/src/main/java/com/drawbluecup/entity/Product.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22

33
import lombok.Data;
44

5+
import java.util.List;
6+
57
@Data
68
public class Product {
79
//成员变量
810
private Integer id;
911
private String name;
12+
private List<Order> orders ;
1013

1114
//构造方法
1215
public Product() {
1316
}
1417

15-
public Product(Integer id, String name) {
18+
public Product(Integer id, String name, List<Order> orders) {
1619
this.id = id;
1720
this.name = name;
21+
this.orders = orders;
1822
}
1923

2024
}

drawbluecup-order/src/main/java/com/drawbluecup/mapper/OrderMapper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public interface OrderMapper {
3030
//增
3131
void addOrder(Order order); //添加订单
3232

33+
//--------------------------------------------------------------------
3334
/**
3435
* 为订单添加商品(向中间表 order_product 插入记录)
3536
* 实现订单与商品的多对多关联
@@ -44,6 +45,7 @@ public interface OrderMapper {
4445
* @param productId 商品ID
4546
*/
4647
void removeProductFromOrder(@Param("orderId") Integer orderId, @Param("productId") Integer productId);
48+
//--------------------------------------------------------------------
4749

4850
//删
4951
void deleteOrderAll(); //删除所有订单

drawbluecup-product/src/main/java/com/drawbluecup/mapper/ProductMapper.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,67 @@
99
@Mapper
1010
public interface ProductMapper {
1111

12-
//查询所有商品信息
12+
/**查询所有商品信息
13+
*
14+
* @return
15+
*/
1316
List<Product> findAll();
14-
//根据id查询商品
17+
18+
/**根据id查询商品
19+
*
20+
* @param id
21+
* @return
22+
*/
23+
1524
Product findById(@Param("id")Integer id);
16-
//根据name查询商品(支持模糊)
25+
26+
/**根据name查询商品(支持模糊)
27+
*
28+
* @param name
29+
* @return
30+
*/
1731
Product findByName(@Param("name")String name);
1832

19-
//删除商品(根据id)
33+
//<======================================================================================>
34+
35+
/**删除商品(根据id)
36+
*
37+
* @param id
38+
*/
2039
void deleteById(@Param("id")Integer id);
21-
//删除所有商品
40+
41+
42+
/**删除所有商品
43+
*
44+
*/
2245
void deleteAll();
2346

47+
//<======================================================================================>
2448

25-
//新增商品
49+
50+
/**新增商品
51+
*
52+
* @param product
53+
*/
2654
void add(Product product);
2755

28-
//更新商品
56+
//<======================================================================================>
57+
58+
59+
/**
60+
* 更新商品
61+
* @param product
62+
*/
2963
void update(Product product);
3064

65+
66+
//<======================================================================================>
67+
68+
/**
69+
* 查询商品及其关联的订单列表(多对多反向查询)
70+
* @param productId 商品ID
71+
* @return 包含订单列表的商品对象
72+
*/
73+
Product findProductWithOrders(@Param("productId") Integer productId);
74+
3175
}

drawbluecup-product/src/main/java/com/drawbluecup/service/ProductService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public interface ProductService {
1313
void deleteAll();
1414
void add(Product product);
1515
void update(Product product);
16+
public Product findProductWithOrders(Integer productId);
1617

1718

1819

drawbluecup-product/src/main/java/com/drawbluecup/service/impl/ProductServiceImpl.java

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
//服务层实现类
1313
//服务层实现类来填充服务层接口的意义(帮助mapper处理业务逻辑),然后控制层来调用服务层接口
14-
//不合理?直接抛异常🤪
14+
//不合理?直接抛异常
1515
@Service
1616
public class ProductServiceImpl implements ProductService {
1717

@@ -26,65 +26,78 @@ public class ProductServiceImpl implements ProductService {
2626

2727
//查询所有商品信息
2828
@Override
29-
public List<Product> findAll(){
29+
public List<Product> findAll() {
3030
//没有检验,如果没有查询到返回空列表
3131
return productMapper.findAll();
3232

3333
}
3434

3535
//根据id查询商品
3636
@Override
37-
public Product findById(Integer id){
37+
public Product findById(Integer id) {
3838
//检验id合法性:ID 不能为 null 或小于 1(非法 ID 直接抛异常)
3939
if (id == null || id <= 0) {
40-
throw new BusinessException(400103,"输入id不可为空或小于0");
40+
throw new BusinessException(400, "输入id不可为空或小于0");
4141
}
42-
return productMapper.findById(id);
4342

43+
Product product = productMapper.findById(id);
44+
45+
// 3. 校验结果:如果查不到记录,抛异常提示
46+
if (product == null) {
47+
throw new BusinessException(404, "查询失败:ID 为 " + id + " 的商品不存在");
48+
}
49+
50+
return product;
4451
}
4552

4653
//根据name查询商品
4754
@Override
48-
public Product findByName(String name){
55+
public Product findByName(String name) {
4956
//检验name合法性:name 不能为 null (非法 直接抛异常)
50-
if (name == null ) {
51-
throw new BusinessException(400103,"输入name不可为空");
57+
if (name == null) {
58+
throw new BusinessException(400103, "输入name不可为空");
5259
}
53-
return productMapper.findByName(name);
60+
Product product = productMapper.findByName(name);
5461

62+
if (product == null) {
63+
throw new BusinessException(404, "查询失败:name 为 " + name + " 的商品不存在");
64+
}
65+
66+
return product;
5567
}
5668

5769

70+
//<======================================================================================>
5871

5972
//以下增删改都是操作数据库,不应该返回数据(返回值为void)
6073

6174

62-
6375
//删除
6476
//删除商品根据id
6577
@Override
66-
public void deleteById(Integer id){
78+
public void deleteById(Integer id) {
6779
//检验id合法性:ID 不能为 null 或小于 1(非法 ID 直接抛异常)
6880
if (id == null || id <= 0) {
69-
throw new BusinessException(400103,"输入id不可为空或小于0");
81+
throw new BusinessException(400, "输入id不可为空或小于0");
7082
}
7183
productMapper.deleteById(id);
7284
}
7385

7486
//删除所有商品
7587
@Override
76-
public void deleteAll(){
88+
public void deleteAll() {
7789

7890
productMapper.deleteAll();
7991
}
8092

8193

94+
//<======================================================================================>
8295

8396

8497
//新增
8598
//新增商品
8699
@Override
87-
public void add(Product product){
100+
public void add(Product product) {
88101
/*检验:
89102
1参数是否合理?整体为null?局部为null?id小于0?
90103
2新增对象里面字段是否可以重复?(商品名不可重复)
@@ -96,38 +109,39 @@ public void add(Product product){
96109

97110
//1.
98111
if (product == null) {
99-
throw new BusinessException(400103,"新增商品不可为空");
112+
throw new BusinessException(400, "新增商品不可为空");
100113
}
101114
if (product.getName() == null) {
102-
throw new BusinessException(400103,"新增商品的商品名不可为空");
115+
throw new BusinessException(400, "新增商品的商品名不可为空");
103116
}
104117

105118

106-
107119
//2.
108-
if( productMapper.findByName(product.getName()) != null ){
109-
throw new BusinessException(400303,"新增商品的商品名已存在");
120+
if (productMapper.findByName(product.getName()) != null) {
121+
throw new BusinessException(400, "新增商品的商品名已存在");
110122
}
111123

112124
productMapper.add(product);
113125
}
114126

127+
//<======================================================================================>
128+
115129

116130
//更新
117131
//更新商品(基于id查询来更新,并不能修改id)
118132
@Override
119-
public void update(Product product){
133+
public void update(Product product) {
120134

121135

122136
// 1. 检验ID的合法性
123137
if (product.getId() == null || product.getId() <= 0) {
124-
throw new BusinessException(400103,"输入id不可为空或小于0");
138+
throw new BusinessException(400, "输入id不可为空或小于0");
125139
}
126140

127141
// 2. 先查询数据库,获取当前要更新的商品信息
128142
Product existingProduct = productMapper.findById(product.getId());//这里不会抛异常,因为调用的时mapper层的方法
129143
if (existingProduct == null) {
130-
throw new BusinessException(400403,"要更新的商品不存在");
144+
throw new BusinessException(404, "要更新的商品不存在");
131145
}
132146

133147
// 3. 检查商品名称是否有变化。如果名称没变,就不需要进行重复校验!
@@ -136,15 +150,14 @@ public void update(Product product){
136150
Product productWithSameName = productMapper.findByName(product.getName());
137151
if (productWithSameName != null) {
138152
// 找到了一个使用新名称的商品,说明名称重复了
139-
throw new BusinessException(400303,"修改商品的商品名已存在");
153+
throw new BusinessException(400, "修改商品的商品名已存在");
140154
}
141155
}
142156

143157
// 5. 所有校验通过,执行更新操作
144158
productMapper.update(product);
145159

146160
/*
147-
148161
//检验id合理?
149162
if (product.getId() == null || product.getId() <= 0) {
150163
throw new BusinessException("输入id不可为空或小于0");
@@ -156,10 +169,27 @@ public void update(Product product){
156169
}
157170
productMapper.update(product);
158171
159-
160-
161172
*/
173+
162174
}
163175

176+
//<======================================================================================>
177+
@Override
178+
public Product findProductWithOrders(Integer productId) {
179+
// 1. 校验商品ID
180+
if (productId == null || productId <= 0) {
181+
throw new BusinessException(400, "商品ID不合法");
182+
}
183+
184+
// 2. 调用Mapper的JOIN查询
185+
Product product = productMapper.findProductWithOrders(productId);
186+
187+
// 3.商品存在?不存在就不要返回了
188+
if (product == null) {
189+
throw new BusinessException(404, "商品不存在");
190+
}
191+
192+
return product;
193+
}
164194

165195
}

0 commit comments

Comments
 (0)