11、买家订单service层构建
前言:DAO就是与数据库交互的增删改查;我们所有功能的逻辑实现呢都放到service层,是这三层里面最复杂的一层,controller层就是用来展示的。这篇文章一定要仔细看到最后哈哈哈哈
(1)新建dto包并且新建OrderDTO类(数据传输转换)
package com.yummy.sell.dto;
import com.yummy.sell.dataobject.OrderDetail;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* @author LYM
* @date 2021/3/5 15:33
*/
@Entity
@Data
@DynamicUpdate
public class OrderDTO {
@Id
/**订单id*/
private String orderId;
/**买家名称*/
private String buyerName;
/**买家电话*/
private String buyerPhone;
/**买家地址*/
private String buyerAddress;
/**买家微信id*/
private String buyerOpenid;
/**订单总额*/
private BigDecimal orderAmount;
/**订单状态,默认0为新订单*/
private Integer orderStatus;
/**支付状态,默认0为未支付*/
private Integer payStatus;
/**创建时间*/
private Date createTime;
/**更新时间*/
private Date updateTime;
List<OrderDetail> orderDetailList;
}
(2)新建OrderService接口
package com.yummy.sell.service;
import com.yummy.sell.dto.OrderDTO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
/**
* @author LYM
* @date 2021/3/5 15:26
*/
public interface OrderService {
/**创建订单*/
OrderDTO create(OrderDTO orderMaster);
/**查询订单*/
OrderDTO findOne(String orderId);
/**查询订单列表*/
Page<OrderDTO> findList(String buyerOpenid, Pageable pageable);
/**取消订单*/
OrderDTO cancel(OrderDTO orderDTO);
/**完结订单*/
OrderDTO finish(OrderDTO orderDTO);
/**支付订单*/
OrderDTO paid(OrderDTO orderDTO);
}
(3)新建OrderServiceImpl实现OrderService接口,在这之前我们需要具备以下其他的工具类
- 随机生成6位数的订单id
package com.yummy.sell.utils;
import java.util.Random;
/**
* @author LYM
* @date 2021/3/5 16:12
*/
public class KeyUtil {
/**
* 生成唯一的主键
* 格式:时间+随机数
* @return
*/
public static String getUniqueKey(){
Random random=new Random ();
//生成随机数位数相等都是6位随机数
Integer a=random.nextInt (900000)+100000;
return System.currentTimeMillis ()+String.valueOf (a);
}
}
(4)OrderServiceImpl类的具体实现
将会先和大家分享一下创建订单是如何实现的
package com.yummy.sell.service.impl;
import com.yummy.sell.dataobject.OrderDetail;
import com.yummy.sell.dataobject.OrderMaster;
import com.yummy.sell.dataobject.ProductInfo;
import com.yummy.sell.dto.CartDTO;
import com.yummy.sell.dto.OrderDTO;
import com.yummy.sell.enums.OrderStatusEnum;
import com.yummy.sell.enums.PayStatusEnum;
import com.yummy.sell.enums.ResultEnum;
import com.yummy.sell.exception.SellException;
import com.yummy.sell.repository.OrderDetailRepository;
import com.yummy.sell.repository.OrderMasterRepository;
import com.yummy.sell.service.OrderService;
import com.yummy.sell.service.ProductService;
import com.yummy.sell.utils.KeyUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author LYM
* @date 2021/3/5 15:39
*/
@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) {
/**
* 1、查询商品(数量,价格,库存是否满足)
* 2、计算总价
* 2、写入订单数据库(orderMaster和orderDetail)
*/
/**初始设置总价为0*/
String orderId=KeyUtil.getUniqueKey ();
BigDecimal orderAmount=new BigDecimal (BigInteger.ZERO);
// List<CartDTO> cartDTOList=new ArrayList<> ();
for(OrderDetail orderDetail:orderDTO.getOrderDetailList ()){
ProductInfo productInfo=productService.findOne (orderDetail.getProductId ());
//如果没有这条信息报异常
if(productInfo==null){
throw new SellException (ResultEnum.PRODUCT_NOT_EXIST);
}
/**计算订单总价*/
orderAmount=productInfo.getProductPrice ()
.multiply (new BigDecimal (orderDetail.getProductQuantity ()))
.add (orderAmount);
/**订单详情入库*/
//设置一个生成随机数的方法
orderDetail.setDetailId (KeyUtil.getUniqueKey ());
orderDetail.setOrderId (orderId);
BeanUtils.copyProperties (productInfo,orderDetail);
orderDetailRepository.save (orderDetail);
// CartDTO cartDTO=new CartDTO (orderDetail.getProductId (),orderDetail.getProductQuantity ());
// cartDTOList.add (cartDTO);
}
//写入订单数据库(orderMaster和orderDetail)
OrderMaster orderMaster=new OrderMaster ();
//这里要先拷贝在进行数据值传送,防止被null值覆盖
BeanUtils.copyProperties (orderDTO,orderMaster);
orderMaster.setOrderId (orderId);
orderMaster.setOrderAmount (orderAmount);
orderMaster.setOrderStatus (OrderStatusEnum.NEW.getCode ());
orderMaster.setPayStatus (PayStatusEnum.WAIT.getCode ());
orderMasterRepository.save (orderMaster);
//扣库存
List<CartDTO> cartDTOList= orderDTO.getOrderDetailList ()
.stream ()
.map (e->new CartDTO (e.getProductId (),e.getProductQuantity ()))
.collect (Collectors.toList ());
//遍历数据并且转换
productService.decreaseStock (cartDTOList);
return null;
}
@Override
public OrderDTO findOne(String orderId) {
return null;
}
@Override
public Page<OrderDTO> findList(String buyerOpenid, Pageable pageable) {
return null;
}
@Override
public OrderDTO cancel(OrderDTO orderDTO) {
return null;
}
@Override
public OrderDTO finish(OrderDTO orderDTO) {
return null;
}
@Override
public OrderDTO paid(OrderDTO orderDTO) {
return null;
}
}
(5)OrderServiceImplTest的单元测试
我们这里先完成一下创建订单的单元测试
package com.yummy.sell.service.impl;
import com.yummy.sell.dataobject.OrderDetail;
import com.yummy.sell.dto.OrderDTO;
import junit.framework.TestCase;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
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.SpringRunner;
import java.util.ArrayList;
import java.util.List;
/**
* @author LYM
* @date 2021/3/5 21:30
*/
@RunWith (SpringRunner.class)
@SpringBootTest
@Slf4j
public class OrderServiceImplTest extends TestCase {
@Autowired
private OrderServiceImpl orderService;
@Test
public void testCreate() {
OrderDTO orderDTO=new OrderDTO ();
orderDTO.setBuyerName ("林雨漫");
orderDTO.setBuyerAddress ("20栋");
orderDTO.setBuyerOpenid ("lym");
orderDTO.setBuyerPhone ("12345678912");
//购物车
List<OrderDetail> orderDetailList=new ArrayList<> ();
OrderDetail orderDetail=new OrderDetail ();
//商品id
orderDetail.setProductId ("1");
//买两件商品
orderDetail.setProductQuantity (2);
orderDetailList.add (orderDetail);
orderDTO.setOrderDetailList (orderDetailList);
OrderDTO result=orderService.create (orderDTO);
log.info ("创建订单");
Assert.assertNotNull (result);
}
public void testFindOne() {
}
public void testFindList() {
}
public void testCancel() {
}
public void testFinish() {
}
public void testPaid() {
}
}
(6)运行测试
原来数据库数据
昨天的文章写到这儿就截然而止了┭┮﹏┭┮,因为昨天在测试过程中遇到了一个问题,导致项目启动失败找了很久的bug还是没有找到原因,便回去睡觉了打算第二天看看。然后第二天终于找到问题根源了不容易啊哈哈哈哈哈
- 我太感动了!终于运行成功但是有一个警告错误
测试结果:
虽然测试结果没有问题,但是每次运行都有刚刚那些错误警告看着着实不舒服哈哈哈,所以我上百度搜了一下看是什么问题。结果如下:
这个给了我一点启发:我们创建订单通过
OrderDTO result=orderService.create (orderDTO);调用create函数本质上就是插入一条数据,如果插入成功那么所返回的结果应该就是一个int型的数据并且不会等于0
- 于是我们修改完善一下OrderServiceImplTest类代码
package com.yummy.sell.service.impl;
import com.yummy.sell.dataobject.OrderDetail;
import com.yummy.sell.dto.OrderDTO;
import junit.framework.TestCase;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
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.SpringRunner;
import java.util.ArrayList;
import java.util.List;
/**
* @author LYM
* @date 2021/3/5 21:30
*/
@RunWith (SpringRunner.class)
@SpringBootTest
@Slf4j
public class OrderServiceImplTest extends TestCase {
@Autowired
private OrderServiceImpl orderService;
@Test
public void testCreate() {
OrderDTO orderDTO=new OrderDTO ();
orderDTO.setBuyerName ("林雨漫");
orderDTO.setBuyerAddress ("20栋");
orderDTO.setBuyerOpenid ("lym");
orderDTO.setBuyerPhone ("12345678912");
//购物车
List<OrderDetail> orderDetailList=new ArrayList<> ();
OrderDetail orderDetail=new OrderDetail ();
orderDetail.setProductId ("2");
orderDetail.setProductQuantity (2);
orderDetailList.add (orderDetail);
orderDTO.setOrderDetailList (orderDetailList);
OrderDTO result=orderService.create (orderDTO);
log.info ("创建订单");
Assert.assertNotEquals (0,result);
}
@Test
public void testFindOne() {
}
@Test
public void testFindList() {
}
@Test
public void testCancel() {
}
@Test
public void testFinish() {
}
@Test
public void testPaid() {
}
}
-
上面的代码测试换成了购买商品id为2的蛋黄酥我们再进行测试一下啊
这下舒服了,测试通过没有一丝错误哈哈哈~ -
我们再看看数据库数据:
我们可以看到商品库存从66正确更新到了64,而且更新时间实时地进行更新
-
我们再看看主订单表信息:
随机生成地订单号以及订单总额对对应上了 -
我们再看看订单详情表数据:
我们可以注意到订单主表与订单详情表的orderId都对应上了!!!
(6)补充说明:
其实上面的有一小部分的代码有点小小bug,也就是我昨天遇到的。
现在我要和大家分享一下昨天是遇到了什么错误,以及上面那个地方有bug以及怎么修改。
- 昨天遇到的问题有
Could not get Connection for extracting meta-data; nested exception is org.springframework.jdbc.Cann
刚开始我以为是我数据库版本的问题导致数据库驱动错误以至于项目启动失败--------然后我就各种更换数据库版本之类的啊,设置配置文件啥的呀,好像还是同一个问题没啥用---------后来12点多了哈哈哈不搞了便睡觉去了
直到今天我又打开项目找我的bug后来啊!我终于发现问题了,问题出现在我的OrderDTO类。也就是这篇文章的第一段代码出现问题了(orderDTO),如下:
其实这段代码之前有报下划线红色,然后我自己神了昨天写这个代码的时候把这个高亮改成了黄色就没有报错了,导致后面测试的时候我一直找不到问题所在(好傻吊啊~)
- 报错的内容大概如下:
‘Basic‘ attribute type should not be a container
由于我的springboot项目中使用的是spring data jpa ,框架会把该属性List<OrderDetail>
当成数据库的一个字段,而不是mysql的数据类型;
- 如何解决:
在这个上面加上一个@OneToMany
注解,表示配置表之间的关系。
这样就完美解决啦!!!
(7)总结
其实我们可以看到OrderServiceImplTest测试类中还有很多方法没有进行测试。其中这个创建订单就是最构件最麻烦的一个,创建订单时涉及到两个表信息的插入,而插入数据都调用各自相应的save方法,然后再数据设置方面:利用BeanUtils.copyProperties (productInfo,orderDetail);
很便捷的将查询到的productInfo数据复制到orderDetail上(前提是字段属性啥的都要保持一致性!)
其次我需要补充说明的一点就是我们在利用这个方法的时候BeanUtils.copyProperties
我们应该注意这段代码放置的先后顺序。因为如果拷贝数据存在null值,原有的值将会被null覆盖掉。比如下面这个:
BeanUtils.copyProperties (orderDTO,orderMaster);
这个一定要先进行拷贝在设置数据属性,不然orderDTO中的null值会将set的值覆盖掉。
这篇文章有点冗长哈哈哈哈,而且信息量有点大,需要慢慢消化才是♥