![]()
📌 背景说明
在“再来一单”业务场景中,需要将历史订单(OrderDetail
)中的菜品信息重新加入当前用户的购物车(ShoppingCart
)。由于两个实体类属性名称和类型基本一致,因此可以使用 Spring 提供的 BeanUtils.copyProperties()
方法快速实现对象间的属性复制。
🧩 涉及类的字段对比
字段 |
OrderDetail |
ShoppingCart |
说明 |
id |
✅ 有 |
✅ 有 |
主键,不复制,避免冲突 |
name |
✅ 有 |
✅ 有 |
菜品或套餐名称 |
dishId |
✅ 有 |
✅ 有 |
菜品 ID |
setmealId |
✅ 有 |
✅ 有 |
套餐 ID |
dishFlavor |
✅ 有 |
✅ 有 |
菜品口味 |
number |
✅ 有 |
✅ 有 |
数量 |
amount |
✅ 有 |
✅ 有 |
单项金额 |
image |
✅ 有 |
✅ 有 |
菜品图片 |
orderId |
✅ 有 |
❌ 无 |
购物车中不需要订单 ID |
userId |
❌ 无 |
✅ 有 |
当前登录用户 ID,需手动设置 |
createTime |
❌ 无 |
✅ 有 |
加入购物车时间,需手动设置 |
🔧 关键代码
List<ShoppingCart> shoppingCartList = orderDetailList.stream().map(x -> {
ShoppingCart shoppingCart = new ShoppingCart();
// 拷贝字段:忽略 id(主键),其余字段只要名字相同都会复制
BeanUtils.copyProperties(x, shoppingCart, "id");
// 设置当前用户ID(在 OrderDetail 中不存在)
shoppingCart.setUserId(userId);
// 设置加入购物车的时间(在 OrderDetail 中不存在)
shoppingCart.setCreateTime(LocalDateTime.now());
return shoppingCart;
}).collect(Collectors.toList());
🛠 技术细节分析
1. BeanUtils.copyProperties(source, target, "id")
- 工具类:
org.springframework.beans.BeanUtils
- 功能:根据字段名和类型相同的匹配原则,将
OrderDetail
中的字段值复制到 ShoppingCart
对象中。
- 忽略字段:
id
不复制,因为两张表的主键不能混用。
- 购物车是与用户强关联的数据,每一条记录都必须记录是哪个用户添加的。
- 当前用户 ID 通过
BaseContext.getCurrentId()
获取。
- 购物车记录通常需要有加入时间以供排序或过期处理。
- 使用当前时间作为购物车项创建时间。
4. stream().map(...).collect(...)
- 利用 Java Stream API 进行集合转换。
map()
方法逐个处理 OrderDetail
项,将其转化为 ShoppingCart
对象。
- 最终收集成
List<ShoppingCart>
结果列表。
✅ 总结
步骤 |
说明 |
1. 查询订单详情 |
根据订单 ID 获取 List<OrderDetail> |
2. 遍历转换 |
使用 Stream 和 BeanUtils.copyProperties 进行字段转换 |
3. 补充字段 |
手动设置 userId 和 createTime |
4. 收集结果 |
转换后的 ShoppingCart 列表用于后续批量插入数据库 |
💡 延伸
- 若需要更灵活地控制字段映射,可以使用 MapStruct 等高级 Bean 映射工具。
- 使用 BeanUtils 的前提是字段名和类型必须匹配,建议在两个类设计时就考虑字段对齐。