02 订单微服务
微服务都是分数据库的。新建个数据库给订单微服务 ,数据库实例名 o2o-order
-- ----------------------------
-- Table structure for order
-- ----------------------------
-- 订单
create table `artisan_order` (
`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`)
);
-- ----------------------------
-- Table structure for order_detail
-- ----------------------------
-- 订单详情
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`)
);
订单与订单详情是一对多的关系,一个订单中可能包含多个订单详情,比如下一个订单,这个订单中买了1杯奶茶、2杯可乐等。
order_detail中不仅设计product_id,同时也冗余 product_name product_price product_icon等,主要是考虑到有些促销活动这些字段会经常更改这些因素。
请求:POST方式 /order/create
"name": "xxx", "phone": "xxxx", "address": "xxxx", "openid": "xxxx", //用户的微信openid "items": [ { "productId": "xxxxxx", "productQuantity": 2 //购买数量 } ]
后端尽量少依赖前端传递的数据,为了安全起见,产品相关的数据,只传递了一个productId和productQuantity,而没有将价格、描述等等一并传递,不传递就不会被篡改,也减少了交互数据的大小。
返回:
{ "code": 0, "msg": "成功", "data": { "orderId": "123456" } }
业务逻辑分析
- 校验前台入参
- 查询商品信息(调用商品微服务)
- 计算订单总价
- 扣减库存(调用商品微服务)
- 订单入库
搭建订单微服务
application.yml
连接到 order微服务的数据库
server: port: 8081 spring: application: name: order datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/o2o_order?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false username: root password: root jpa: show-sql: true eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
application.yml中配置了Eureka的信息后,我们在启动类增加@EnableEurekaClient即可
package com.smart.order; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
实体类
Order
package com.smart.order.domain; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import java.math.BigDecimal; import java.util.Date; @Data @Entity @Table(name="t_order") public class Order { @Id private String orderId; private String buyerName; private String buyerPhone; private String buyerAddress; private String buyerOpenid; private BigDecimal orderAmount; /** * 订单状态, 默认为0新下单. */ private Integer orderStatus; /** * 支付状态, 默认为0未支付. */ private Integer payStatus; private Date createTime; private Date updateTime; }
OrderDetail
package com.smart.order.domain; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import java.math.BigDecimal; @Data @Entity @Table(name="order_detail") public class OrderDetail { @Id private String detailId; private String orderId; private String productId; private String productName; private BigDecimal productPrice; private Integer productQuantity; private String prodductIcon; }
Dao层 : 创建订单无非就是往这两个表里写入数据。直接利用jpa提供的save方法即可。
OrderRepository
空实现 ,利用jpa本身提供的save方法
package com.smart.order.Repository; import com.smart.order.domain.Order; import org.springframework.data.jpa.repository.JpaRepository; public interface OrderRepository extends JpaRepository<Order,String> { }
OrderDetailRepository
空实现 ,利用jpa本身提供的save方法
package com.smart.order.Repository; import com.smart.order.domain.OrderDetail; import org.springframework.data.jpa.repository.JpaRepository; public interface OrderDedetailRepository extends JpaRepository<OrderDetail,String> { }
Service层
根据业务规则,一个Order中可能有多个OrderDetail, 所以入参OrderDetail 必须是个集合, 因此将这俩合并一下,封装成DTO来使用,作为入参和返回结果。
package com.smart.order.domain; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data public class OrderDTO { private String orderId; private String buyerName; private String buyerPhone; private String buyerAddress; private String buyerOpenid; private BigDecimal orderAmount; private Integer orderStatus; private Integer payStatus; /** * 一个订单有多个orderDetail */ List<OrderDetail> orderDetailList; }
OrderService接口和实现类
先实现订单入库部分
package com.smart.order.service.impl; import com.smart.order.Repository.OrderDedetailRepository; import com.smart.order.Repository.OrderRepository; import com.smart.order.constant.OrderStatus; import com.smart.order.constant.PayStatus; import com.smart.order.domain.Order; import com.smart.order.domain.OrderDTO; import com.smart.order.service.OrderService; import com.smart.order.utils.KeyUtil; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; @Service public class OrderServiceImpl implements OrderService { @Autowired private OrderRepository orderRepository; @Autowired private OrderDedetailRepository orderDedetailRepository; @Override public OrderDTO createOrder(OrderDTO orderDTO) { //查询商品信息 //计算订单总价 //减库存 //订单入库 Order order = new Order(); orderDTO.setOrderId(KeyUtil.genUniqueKey()); BeanUtils.copyProperties(orderDTO,order); order.setOrderAmount(new BigDecimal(100)); order.setOrderStatus(OrderStatus.NEW.getCode()); order.setPayStatus(PayStatus.WAIT.getCode()); orderRepository.save(order); return orderDTO; } }
Controller层
package com.smart.order.domain; import lombok.Data; import javax.validation.constraints.NotEmpty; /** * 对应: * { * "name":"xxx", * "phone":"xxx", * "address":"xxx", * "openid":"xxx", * "items":[ * "productId":"xxxx", * "productQuantity":"2" * ] * } */ @Data public class OrderForm { @NotEmpty(message="姓名必填") private String name; @NotEmpty(message="电话必填") private String phone; @NotEmpty(message="地址必填") private String address; @NotEmpty(message="openid必填") private String openid; @NotEmpty(message="购物车不能为空") private String items; }
package com.smart.order.converter; import com.alibaba.fastjson.JSONObject; import com.smart.order.domain.OrderDTO; import com.smart.order.domain.OrderDetail; import com.smart.order.domain.OrderForm; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; @Slf4j public class OrderForm2OrderDTOConverter { public static OrderDTO convert(OrderForm orderForm){ OrderDTO orderDTO = new OrderDTO(); orderDTO.setBuyerName(orderForm.getName()); orderDTO.setBuyerPhone(orderForm.getPhone()); orderDTO.setBuyerAddress(orderForm.getAddress()); orderDTO.setBuyerOpenid(orderForm.getOpenid()); List<OrderDetail> orderDetails = new ArrayList<>(); orderDetails = JSONObject.parseArray(orderForm.getItems(), OrderDetail.class); orderDTO.setOrderDetailList(orderDetails); return orderDTO; } }
package com.smart.order.controller; import com.smart.order.constant.ErrorCode; import com.smart.order.converter.OrderForm2OrderDTOConverter; import com.smart.order.domain.OrderDTO; import com.smart.order.domain.OrderForm; import com.smart.order.exception.OrderException; import com.smart.order.service.OrderService; import com.smart.order.vo.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/order") @Slf4j public class OrderController { @Autowired private OrderService orderService; /** * 创建订单 * @param orderForm * @param bindingResult * @return */ @PostMapping("/create") public Result createOrder(@Valid OrderForm orderForm, BindingResult bindingResult){ if(bindingResult.hasErrors()){ log.error("createOrder的参数不正确:{}",orderForm); throw new OrderException(ErrorCode.PARAM_ERROR.getCode(),bindingResult.getFieldError().getDefaultMessage()); } OrderDTO orderDTO = OrderForm2OrderDTOConverter.convert(orderForm); if(CollectionUtils.isEmpty(orderDTO.getOrderDetailList())){ log.error("createOrder的购物车为空"); throw new OrderException(ErrorCode.CART_EMPTY); } OrderDTO order = orderService.createOrder(orderDTO); Map<String,String> result=new HashMap<>(); result.put("orderId",order.getOrderId()); return Result.success(result); } }
测试

参考:
https://blog.csdn.net/yangshangwei/article/details/88762602
浙公网安备 33010602011771号