文章目录
一、 OrderDTO
这个类为数据传输层类,在各个层之间传输
因为想在OrderMaster类中查出所有的OrderDetail(订单详情),但是OrderMaster表中没有order_detail这个字段,所以使用OrderDTO,在原有的OrderMaster类的属性基础上加上orderDetailList
/**
* 数据传输对象,在各个层之间传输使用,这里为了加上orderDetailList
* 因为数据库中没有这个字段,所以不能加在OrderDetail类中
*/
@Data
public class OrderDTO {
//订单Id
@Id
private String orderId;
//买家名字
private String buyerName;
//买家电话
private String buyerPhone;
//买家地址
private String buyerAddress;
//买家微信openid
private String buyerOpenid;
//订单总金额
private BigDecimal orderAmount;
//订单状态,默认为0:下单
private Integer orderStatus;
//支付状态,默认为0:未支付
private Integer payStatus;
//创建时间
private Date createTime;
//更新时间
private Date updateTime;
//订单详情列表
List<OrderDetail> orderDetailList;
}
二、OrderService
/**
* 使用OrderDTO这个对象是因为里面有orderDetailList属性
* 一个订单下面可以有多个商品
*/
public interface OrderService {
/**
* 创建订单
* @param orderDTO
* @return
*/
OrderDTO create(OrderDTO orderDTO);
/**
* 查询单个订单
* @param orderId
* @return
*/
OrderDTO findOnes(String orderId);
/**
* 查询订单列表
* @param buyerOpenid
* @param pageable
* @return
*/
Page<OrderDTO> findList(String buyerOpenid, Pageable pageable);
/**
* 取消订单
* @param orderDTO
* @return
*/
OrderDTO cancel(OrderDTO orderDTO);
/**
* 完结订单
* @param orderDTO
* @return
*/
OrderDTO finish(OrderDTO orderDTO);
/**
* 支付订单
* @param orderDTO
* @return
*/
OrderDTO paid(OrderDTO orderDTO);
}
三、 OrderServiceImpl中创建订单的实现
这个创建订单里面里面有很多逻辑和内容,理解起来较为困难:
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMasterRepository repository;
@Autowired
private ProductService productService;
@Autowired
private OrderDetailRepository orderDetailRepository;
@Autowired
private OrderMasterRepository orderMasterRepository;
@Transactional
@Override
public OrderDTO create(OrderDTO orderDTO) {
//初始化商品总价为0
BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO);
//订单创建时生成订单编号orderId
String orderId = KeyUtil.genUniqueKey();
//1.查询商品
List<OrderDetail> orderDetailList = orderDTO.getOrderDetailList();
for(OrderDetail orderDetail:orderDetailList){
ProductInfo productInfo = productService.findOne(orderDetail.getProductId());
if(productInfo == null){
throw new SellException(ResultEnum.PRODUCT_NOT_EXIST);
}
//2.计算订单总价:每一件商品的价格的和即为这个订单的价格
orderAmount = productInfo.getProductPrice()
.multiply(new BigDecimal(orderDetail.getProductQuantity()))
.add(orderAmount);
//3.订单详情入库(OrderDetail)
orderDetail.setDetailId(KeyUtil.genUniqueKey());
orderDetail.setOrderId(orderId);
BeanUtils.copyProperties(productInfo,orderDetail);
orderDetailRepository.save(orderDetail);
}
//4.写入订单数据库(OrderMaster)
OrderMaster orderMaster = new OrderMaster();
BeanUtils.copyProperties(orderDTO,orderMaster);
orderMaster.setOrderId(orderId);
orderMaster.setOrderAmount(orderAmount);
orderMaster.setOrderStatus(OrderStatuEnum.NEW.getCode());
orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode());
orderMasterRepository.save(orderMaster);
//5.扣库存
List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream()
.map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
.collect(Collectors.toList());
productService.decreaseStock(cartDTOList);
return orderDTO;
}
}
1. 查询商品
这个表包括买家的所有订单:
这个表包括买家每个订单下面的所有商品,比如订单号order_id=123456
下面有两件商品鸡翅和皮蛋粥:
这个表包括每个订单下面的每个商品的信息:
创建订单的第一步是查询商品的信息:
1、首先通过orderDTO对象(这个对象就是OrderMaster对象的传输对象,可以看做OrderMaster对象)从数据库中查询出买家的所有订单:
2、查出买家所有的订单以后,遍历所有的订单,通过ProductService总的findOne()方法,通过productId查询出商品信息:
这里如果查出的商品信息为null,就抛出异常:商品不存在
/**
* 返回给前端提示的异常报告消息
*/
@Getter
@AllArgsConstructor
public enum ResultEnum {
PRODUCT_NOT_EXIST(10,"商品不存在"),
PRODUCT_STOCK_ERROR(11,"库存不正确"),
;
private Integer code;
private String message;
}
/**
* 异常类,根据异常状态报异常
*/
public class SellException extends RuntimeException{
private Integer code;
private String message;
public SellException(ResultEnum resultEnum){
//将message的内容传入父类的构造方法中
super(resultEnum.getMessage());
this.code=resultEnum.getCode();
}
}
2. 计算订单总价
已经查询出了每件商品的信息,通过每件商品的价格乘以订单中该件商品的数量就可以得到订单的总价:
3. 订单详情入库
现在是买家买东西,我们为买家创建订单,包括detail_id,订单号(order_id),商品号(product_id),商品名称(product_name),商品价格(product_price),商品图片(product_icon)等,买家选择好以后要将这些生成一个订单写入数据库:
这里使用BeanUtils(Object source,Object target):将一个对象属性和值拷贝到另一个对象的属性中。
同时订单号是随机生成的:
/**
* 生成唯一的主键:时间+随机数
*/
public class KeyUtil {
public static synchronized String genUniqueKey(){
Random random = new Random();
//生成6位随机数
int a = random.nextInt(900000) + 100000;
return System.currentTimeMillis()+String.valueOf(a);
}
}
4. 买家订单入库
将买家创建的所有订单写入数据库:包括订单总价(order_amount),订单号(open_id),等等
是不是有点乱?理一理:
首先:一个订单号order_id下面可以有多个订单(detail_id):比如说你同时买了薯条(detail_id)和鸡翅(detail_id),那么一个order_id里面就包括两个detail_id。
其次:每个detail_id都对应一个product_id,即对应一件商品,通过这个product_id就可以得到商品信息
因此:当买了薯条后产生的订单要写入数据库(order_detail),买了鸡翅后产生的订单也要写入数据库(order_detail),然后一起下单写入数据库(order_Master)。
5. 减库存
当买家订单创建完以后要扣库存:
购物车,里面有添加的商品id(product_id表),以及添加的商品数量(order_detail表)
/**
* 购物车
*/
@Data
@AllArgsConstructor
public class CartDTO {
//商品Id
private String productId;
//商品数量
private Integer productQuantity;
}
在productService中增加两个方法:加库存和减库存:
//加库存
void increaseStock(List<CartDTO> cartDTOList);
//减库存
void decreaseStock(List<CartDTO> cartDTOList);
在ProductServiceImpl中添加实现类:
@Transactional
@Override
public void increaseStock(List<CartDTO> cartDTOList) {
}
@Transactional
@Override
public void decreaseStock(List<CartDTO> cartDTOList) {
for(CartDTO cartDTO:cartDTOList){
ProductInfo productInfo = repository.getOne(cartDTO.getProductId());
if(productInfo==null){
throw new SellException(ResultEnum.PRODUCT_NOT_EXIST);
}
Integer result = productInfo.getProductStock()-cartDTO.getProductQuantity();
if(result<0){
throw new SellException(ResultEnum.PRODUCT_STOCK_ERROR);
}
productInfo.setProductStock(result);
repository.save(productInfo);
}
}
四、OrderServiceImplTest
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
class OrderServiceImplTest {
@Autowired
private OrderService orderService;
@Test
void create() {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setBuyerName("师兄");
orderDTO.setBuyerAddress("北京");
orderDTO.setBuyerPhone("137659863");
orderDTO.setBuyerOpenid("110110");
//购物车
List<OrderDetail> orderDetailList = new ArrayList<>();
OrderDetail o1 = new OrderDetail();
//数据库中必须存在
o1.setProductId("123458");
o1.setProductQuantity(1);
orderDetailList.add(o1);
OrderDetail o2 = new OrderDetail();
//数据库中必须存在
o2.setProductId("123457");
o2.setProductQuantity(2);
orderDetailList.add(o2);
orderDTO.setOrderDetailList(orderDetailList);
OrderDTO result = orderService.create(orderDTO);
log.info("创建订单 result={}",result);
}
}