买家订单(OrderMaster)
5.1、 流程一览
- 实体类
- 两个实体类 OrderMaster.java和OrderDetail.java
- 写了两个状态枚举类 OrderStatusEnum.java、PayStatusEnum.java
- dao接口
- OrderMasterRepository.java和OrderDetailRepository.java
- 测试类
- service层
- OrderService.java
- OrderDTO //数据传输对象(DTO是数据库中不存在的库,但代码中需要)
- OrderServiceImpl.java
- SellException.java // 错误信息
- ResultEnum.java // 结果枚举
- keyUtil.java // 随机数生成工具 时间戳(毫秒)+随机六位数
- CartDTO.java// 购物车对象
- 测试OrderServiceImpl
5.2 dao接口和测试类
5.2.1 OrderMasterRepository,查询回来结果按页查找
参数传入一个Pageable 对象
public interface OrderMasterRepository extends JpaRepository<OrderMaster, String>{
// 通过id分页查找
Page<OrderMaster> findByBuyerOpenid(String buyerOpenid, Pageable pageable);
}
5.2.2 OrderMasterRepository的测试类
但测试类中,传入的是PageRequest
因为PageRequest 继承一个抽象类,该抽象类又继承了Pageable
这里注意测试类的带page信息的测试方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderMasterRepositoryTest {
@Autowired
private OrderMasterRepository repository;
@Test
public void findByBuyerOpenid() throws Exception {
PageRequest request = new PageRequest(0,3); //获取第一页,获取3条记录
Page<OrderMaster> result = repository.findByBuyerOpenid("110110", request);
System.out.println(result.getTotalElements());
Assert.assertNotEquals(0,result.getTotalElements());
}
}
5.3 service层
5.3.1 OrderService
写一个OrderService的接口,因为一个订单会对应多个商品详细,为了方便,应该在OrderMaster实体类中,增加一个List,
但是这个List在数据库中并木有数据,@transient标签可以在对应数据库生成对象时,忽略该变量。
@Transient // 对应数据库时 忽略
private List<OrderDetail> orderDetailList;
但一般不这样直接添加在原service上,而是建立一个dto类,OrderDTO.java
5.3.2 OrderDTO
DTO ---- date transform Object // 数据传输对象
该实体类和OrderMaster一毛一样,然后多一个orderDetailList变量
@Data
@DynamicUpdate //自动更新时间
public class OrderDTO {
... // 内容和OrderMaster一毛一样,就多下面这一行
private List<OrderDetail> orderDetailList;
}
5.3.3 OrderServiceImpl
ProductServiceImpl.java中添加减库存的具体操作
@Service //service端的注解
public class ProductServiceImpl implements ProductService {
@Autowired
ProductinfoRepository repository ;
@Override
@Transactional // 事务回滚,如果操作失败,扔出error然后啥都不操作
public void decreaseStock(List<CartDTO> cartDTOList) {
for(CartDTO cartDTO : cartDTOList) {
ProductInfo productInfo= repository.findOne(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);
}
}
}
OrderServiceImpl.java 中新建订单的代码
代码中多次使用lambda表达式,要多看,不容易看懂
用lambda表达式之前,都是先建一个购物车的list,然后for循环中向list中add对象,id和数量,
使用lambda表达式后,代码部分
@Service
public class OrderServiceImpl implements OrderService {
@Override
@Transactional //事务回滚
public OrderDTO create(OrderDTO orderDTO) {
for(OrderDetail orderDetail : orderDTO.getOrderDetailList()) {
}
// 4.下单成功,减库存
// 用lambda表达式
List<CartDTO> cartDTOList= orderDTO.getOrderDetailList().stream().map(e ->
new CartDTO(e.getProductId(), e.getProductQuantity())
).collect(Collectors.toList());
orderDTO.getOrderDetailList();
productService.decreaseStock(cartDTOList);
return orderDTO;
}
}
OrderServiceImpl .java 新增订单完整代码
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private ProductService productService;
@Autowired
private OrderDetailRepository orderDetailRepository;
@Autowired
private OrderMasterRepository orderMasterRepository;
@Override
@Transactional //事务回滚
public OrderDTO create(OrderDTO orderDTO) {
// 一开始创建订单的时候就生成了订单id
String orderId = KeyUtil.genUniqueKey();
// 初始总价是0
BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO);
// 存放购物车中详情的list ,但一般不用这种方法
// List<CartDTO> cartDTOList = new ArrayList<>();
// 1. 查询商品(数量,价格)
for(OrderDetail orderDetail : orderDTO.getOrderDetailList()) {
ProductInfo productInfo = productService.findOne(orderDetail.getProductId());
if(productInfo == null){
throw new SellException(ResultEnum.PRODUCT_NOT_EXIST);
}
// 2.计算订单总价
orderAmount = orderDetail.getProductPrice()
.multiply(new BigDecimal(orderDetail.getProductQuantity()))
.add(orderAmount);
// 3.订单详情入库(页面只传id和quantity数量)
orderDetail.setDetailId(KeyUtil.genUniqueKey()); // 原来详情中商品的id是自己生成的??
orderDetail.setOrderId(orderId);
// 拷贝productInfo中的属性
BeanUtils.copyProperties(productInfo, orderDetail);
orderDetailRepository.save(orderDetail);
// 信息写入购物车,但一般不用这种方法
// CartDTO cartDTO = new CartDTO(orderDetail.getProductId(), orderDetail.getProductQuantity());
// cartDTOList.add(cartDTO);
}
// 3.写入订单数据库(orderMaster和orderDetail都要写入)
OrderMaster orderMaster = new OrderMaster();
orderMaster.setOrderId(orderId);
orderMaster.setOrderAmount(orderAmount);
// 拷贝数据
BeanUtils.copyProperties(orderDTO, orderMaster);
// 写入数据看
orderMasterRepository.save(orderMaster);
// 4.下单成功,减库存
// 用lambda表达式
List<CartDTO> cartDTOList= orderDTO.getOrderDetailList().stream().map(e ->
new CartDTO(e.getProductId(), e.getProductQuantity())
).collect(Collectors.toList());
orderDTO.getOrderDetailList();
productService.decreaseStock(cartDTOList);
return orderDTO;
}
}
5.3.4 SellException 错误类
从ResultEnum 读需要返回的错误信息。
public class SellException extends RuntimeException{
private Integer code;
public SellException(ResultEnum resultEnum) {
super(resultEnum.getMessage());
this.code = resultEnum.getCode();
}
}
5.3.5 keyUtil .java 生成随机数
注意加锁!!光是时间戳不够!!
public class keyUtil {
/**
* 生成唯一主键
* 格式:时间+随机数
* */
public static synchronized String genUniqueKey() {
Random random = new Random();
Integer number = random.nextInt(900000)+100000; //生成6位随机数
return System.currentTimeMillis() + String.valueOf(number);
}
}