1.创建订单api,如下:

2.创建订单实现逻辑

3.新建订单、订单商品表
-- 订单 create table `order_master` ( `order_id` varchar(32) not null, `buyer_name` varchar(32) not null comment '买家名字', `buyer_phone` varchar(32) not null comment '买家电话', `buyer_address` varchar(128) not null comment '买家地址', `buyer_openid` varchar(64) not null comment '买家微信openid', `order_amount` decimal(8,2) not null comment '订单总金额', `order_status` tinyint(3) not null default '0' comment '订单状态, 默认为新下单', `pay_status` tinyint(3) not null default '0' comment '支付状态, 默认未支付', `create_time` timestamp not null default current_timestamp comment '创建时间', `update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间', primary key (`order_id`), key `idx_buyer_openid` (`buyer_openid`) ); -- 订单商品 create table `order_detail` ( `detail_id` varchar(32) not null, `order_id` varchar(32) not null, `product_id` varchar(32) not null, `product_name` varchar(64) not null comment '商品名称', `product_price` decimal(8,2) not null comment '当前价格,单位分', `product_quantity` int not null comment '数量', `product_icon` varchar(512) comment '小图', `create_time` timestamp not null default current_timestamp comment '创建时间', `update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间', primary key (`detail_id`), key `idx_order_id` (`order_id`) ); |
4.在IDEA新建springCloud项目-订单服务



修改版本,和之前建的eureka项目版本一致,修改完记得刷新:

删除掉不需要的文件:

5.把订单服务注册到eureka上去,启动项目
将application.properties修改为application.yml

记得加上这个注解,再启动项目:

打开8761的eureka,有如下页面则成功将订单服务注册到8761的eureka上:

6.商品业务实现
在pom.xml添加spring-boot-starter-data-jpa和mysql-connector-java依赖,且刷新:

在application.yml配置数据库信息:
(加jpa.show-sql:true,可在测试环境显示sql)

新建订单相关常量:
新建订单支付相关常量:
新建KeyUtil.java,生成唯一的主键,这个不能保证完完全全唯一,只是简单用下,如果是正式项目,需要作为一个独立的服务来生成key:
KeyUtil.java
public class KeyUtil { /** * 生成唯一的主键 * 格式: 时间+随机数 */ public static synchronized String genUniqueKey() { Random random = new Random(); Integer number = random.nextInt(900000) + 100000; return System.currentTimeMillis() + String.valueOf(number); } } |
新建ResultVO.java
ResultVO.java
@Data public class ResultVO<T> { private Integer code; private String msg; private T data; } |
1) model 配置表对应的实体类,类名、字段最好和表中一致
a.使用这个插件,可以省略getter/setter方法
在pom.xml加入lombok依赖  还需要在idea下载这个插件  只需要在实体类加上@Data注解,就可以不用在实体类生成getter/setter方法了 |
添加依赖:

新建OrderException.java
OrderException.java
public class OrderException extends RuntimeException { private Integer code; public OrderException(Integer code, String message) { super(message); this.code = code; } public OrderException(ResultEnum resultEnum) { super(resultEnum.getMessage()); this.code = resultEnum.getCode(); } } |
新建实体类OrderDetail.java、OrderMaster.java、OrderDTO.java
OrderDetail.java
@Data @Entity public class OrderDetail { @Id private String detailId; /** 订单id. */ private String orderId; /** 商品id. */ private String productId; /** 商品名称. */ private String productName; /** 商品单价. */ private BigDecimal productPrice; /** 商品数量. */ private Integer productQuantity; /** 商品小图. */ private String productIcon; } |
OrderMaster.java
@Data @Entity public class OrderMaster { /** 订单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; } |
OrderDTO.java
@Data public class OrderDTO { /** 订单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 List<OrderDetail> orderDetailList; } |
2) dao
新建OrderMasterRepository.java、OrderDetailRepository.java
OrderMasterRepository.java
public interface OrderMasterRepository extends JpaRepository<OrderMaster, String> { //里面方法是不需要写的,直接用就好了 } |
OrderDetailRepository.java
public interface OrderDetailRepository extends JpaRepository<OrderDetail, String> { List<OrderDetail> findByOrderId(String orderId); } |
3) service
新建OrderService.java、OrderServiceImpl.java
OrderService.java
public interface OrderService { /** * 创建订单 * @param orderDTO * @return */ OrderDTO create(OrderDTO orderDTO); /** * 完结订单(只能卖家操作) * @param orderId * @return */ OrderDTO finish(String orderId); } |
OrderServiceImpl.java
@Service public class OrderServiceImpl implements OrderService { @Autowired private OrderDetailRepository orderDetailRepository; @Autowired private OrderMasterRepository orderMasterRepository; @Autowired private ProductClient productClient; @Override @Transactional public OrderDTO create(OrderDTO orderDTO) { String orderId = KeyUtil.genUniqueKey(); //查询商品信息(调用商品服务) List<String> productIdList = orderDTO.getOrderDetailList().stream() .map(OrderDetail::getProductId) .collect(Collectors.toList()); List<ProductInfoOutput> productInfoList = productClient.listForOrder(productIdList); //计算总价 BigDecimal orderAmout = new BigDecimal(BigInteger.ZERO); for (OrderDetail orderDetail: orderDTO.getOrderDetailList()) { for (ProductInfoOutput productInfo: productInfoList) { if (productInfo.getProductId().equals(orderDetail.getProductId())) { //单价*数量 orderAmout = productInfo.getProductPrice() .multiply(new BigDecimal(orderDetail.getProductQuantity())) .add(orderAmout); BeanUtils.copyProperties(productInfo, orderDetail); orderDetail.setOrderId(orderId); orderDetail.setDetailId(KeyUtil.genUniqueKey()); //订单详情入库 orderDetailRepository.save(orderDetail); } } } //扣库存(调用商品服务) List<DecreaseStockInput> decreaseStockInputList = orderDTO.getOrderDetailList().stream() .map(e -> new DecreaseStockInput(e.getProductId(), e.getProductQuantity())) .collect(Collectors.toList()); productClient.decreaseStock(decreaseStockInputList); //订单入库 OrderMaster orderMaster = new OrderMaster(); orderDTO.setOrderId(orderId); BeanUtils.copyProperties(orderDTO, orderMaster); orderMaster.setOrderAmount(orderAmout); orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode()); orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode()); orderMasterRepository.save(orderMaster); return orderDTO; } @Override @Transactional public OrderDTO finish(String orderId) { //1. 先查询订单 Optional<OrderMaster> orderMasterOptional = orderMasterRepository.findById(orderId); if (!orderMasterOptional.isPresent()) { throw new OrderException(ResultEnum.ORDER_NOT_EXIST); } //2. 判断订单状态 OrderMaster orderMaster = orderMasterOptional.get(); if (OrderStatusEnum.NEW.getCode() != orderMaster.getOrderStatus()) { throw new OrderException(ResultEnum.ORDER_STATUS_ERROR); } //3. 修改订单状态为完结 orderMaster.setOrderStatus(OrderStatusEnum.FINISHED.getCode()); orderMasterRepository.save(orderMaster); //查询订单详情 List<OrderDetail> orderDetailList = orderDetailRepository.findByOrderId(orderId); if (CollectionUtils.isEmpty(orderDetailList)) { throw new OrderException(ResultEnum.ORDER_DETAIL_NOT_EXIST); } OrderDTO orderDTO = new OrderDTO(); BeanUtils.copyProperties(orderMaster, orderDTO); orderDTO.setOrderDetailList(orderDetailList); return orderDTO; } } |
4) form
新建OrderForm.java,需要表单验证,所以不用vo:
OrderForm.java
@Data public class OrderForm { /** * 买家姓名 */ @NotEmpty(message = "姓名必填") private String name; /** * 买家手机号 */ @NotEmpty(message = "手机号必填") private String phone; /** * 买家地址 */ @NotEmpty(message = "地址必填") private String address; /** * 买家微信openid */ @NotEmpty(message = "openid必填") private String openid; /** * 购物车 */ @NotEmpty(message = "购物车不能为空") private String items; } |
4) form转换dto
新建OrderForm2OrderDTOConverter.java
OrderForm2OrderDTOConverter.java
@Slf4j public class OrderForm2OrderDTOConverter { public static OrderDTO convert(OrderForm orderForm) { Gson gson = new Gson(); OrderDTO orderDTO = new OrderDTO(); orderDTO.setBuyerName(orderForm.getName()); orderDTO.setBuyerPhone(orderForm.getPhone()); orderDTO.setBuyerAddress(orderForm.getAddress()); orderDTO.setBuyerOpenid(orderForm.getOpenid()); List<OrderDetail> orderDetailList = new ArrayList<>(); try { orderDetailList = gson.fromJson(orderForm.getItems(), new TypeToken<List<OrderDetail>>() { }.getType()); } catch (Exception e) { log.error("【json转换】错误, string={}", orderForm.getItems()); throw new OrderException(ResultEnum.PARAM_ERROR); } orderDTO.setOrderDetailList(orderDetailList); return orderDTO; } } |
5) controller
新建ProductController.java
ProductController.java
@RestController @RequestMapping("/order") @Slf4j public class OrderController { @Autowired private OrderService orderService; /** * 1. 参数检验 * 2. 查询商品信息(调用商品服务) * 3. 计算总价 * 4. 扣库存(调用商品服务) * 5. 订单入库 */ @PostMapping("/create") public ResultVO<Map<String, String>> create(@Valid OrderForm orderForm, BindingResult bindingResult) { if (bindingResult.hasErrors()){ log.error("【创建订单】参数不正确, orderForm={}", orderForm); throw new OrderException(ResultEnum.PARAM_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage()); } // orderForm -> orderDTO OrderDTO orderDTO = OrderForm2OrderDTOConverter.convert(orderForm); if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) { log.error("【创建订单】购物车信息为空"); throw new OrderException(ResultEnum.CART_EMPTY); } OrderDTO result = orderService.create(orderDTO); Map<String, String> map = new HashMap<>(); map.put("orderId", result.getOrderId()); return ResultVOUtil.success(map); } /** * 完结订单 * @param orderId * @return */ @PostMapping("/finish") public ResultVO<OrderDTO> finish(@RequestParam("orderId") String orderId) { return ResultVOUtil.success(orderService.finish(orderId)); } } |
7.访问成功