目录:
(1)搭建service-order-client模块
(2)微服务之间用户信息传递
(3)在web-all模块中添加接口
(4)下订单
(1)搭建service-order-client模块
搭建过程同service-cart-client
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-client</artifactId>
<version>1.0</version>
</parent>
<version>1.0</version>
<artifactId>service-order-client</artifactId>
<packaging>jar</packaging>
<name>service-order-client</name>
<description>service-order-client</description>
</project>
在service-order-client暴露接口
package com.atguigu.gmall.order.client;
@FeignClient(value = "service-order", fallback = OrderDegradeFeignClient.class)
public interface OrderFeignClient {
@GetMapping("/api/order/auth/trade")
Result<Map<String, Object>> trade();
}
package com.atguigu.gmall.order.client.impl;
@Component
public class OrderDegradeFeignClient implements OrderFeignClient {
@Override
public Result<Map<String, Object>> trade() {
return Result.fail();
}
}
(2)微服务之间用户信息传递
如上图:因为微服务之间并没有传递头文件,所以我们可以定义一个拦截器,每次微服务调用之前都先检查下头文件,将请求的头文件中的用户信息再放入到header中,再调用其他微服务即可。
在web-util中添加拦截器
package com.atguigu.gmall.common.interceptor;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Component
public class FeignInterceptor implements RequestInterceptor {
public void apply(RequestTemplate requestTemplate){
// 微服务远程调用使用feign ,feign 传递数据的时候,没有。
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 添加header 数据
requestTemplate.header("userTempId", request.getHeader("userTempId"));
requestTemplate.header("userId", request.getHeader("userId"));
}
}
配置网关
- id: web-order
uri: lb://web-all
predicates:
- Host=order.gmall.com- id: service-order
uri: lb://service-order
predicates:
- Path=/*/order/**
(3)在web-all模块中添加接口
<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-order-client</artifactId>
<version>1.0</version>
</dependency>
在web-all中添加控制器
package com.atguigu.gmall.all.controller;
@Controller
public class OrderController {
@Autowired
private OrderFeignClient orderFeignClient;
/**
* 确认订单
* @param model
* @return
*/
@GetMapping("trade.html")
public String trade(Model model) {
Result<Map<String, Object>> result = orderFeignClient.trade();
//addAllAttributes会把里面的map拆分成一个个键值对传过去
model.addAllAttributes(result.getData());
return "order/trade";
}
}
跳转到结算页:
(4)下订单
下单功能分析:
- 保存单据前要做记录:验库存,验价格
- 保存单据: orderInfo orderDetail。
- 保存以后把购物车中的商品删除。{演示不删!}
- 重定向到支付页面。
实体类:OrderInfo
package com.atguigu.gmall.model.order;
import com.atguigu.gmall.model.activity.ActivityRule;
import com.atguigu.gmall.model.activity.CouponInfo;
import com.atguigu.gmall.model.base.BaseEntity;
import com.atguigu.gmall.model.enums.ActivityType;
import com.atguigu.gmall.model.enums.CouponType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@ApiModel(description = "订单信息")
@TableName("order_info")
public class OrderInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "收货人")
@TableField("consignee")
private String consignee;
@ApiModelProperty(value = "收件人电话")
@TableField("consignee_tel")
private String consigneeTel;
@ApiModelProperty(value = "总金额")
@TableField("total_amount")
private BigDecimal totalAmount;
@ApiModelProperty(value = "订单状态")
@TableField("order_status")
private String orderStatus;
@ApiModelProperty(value = "用户id")
@TableField("user_id")
private Long userId;
@ApiModelProperty(value = "付款方式")
@TableField("payment_way")
private String paymentWay;
@ApiModelProperty(value = "送货地址")
@TableField("delivery_address")
private String deliveryAddress;
@ApiModelProperty(value = "订单备注")
@TableField("order_comment")
private String orderComment;
@ApiModelProperty(value = "订单交易编号(第三方支付用)")
@TableField("out_trade_no")
private String outTradeNo;
@ApiModelProperty(value = "订单描述(第三方支付用)")
@TableField("trade_body")
private String tradeBody;
@ApiModelProperty(value = "创建时间")
@TableField("create_time")
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date createTime;
@ApiModelProperty(value = "失效时间")
@TableField("expire_time")
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date expireTime;
@ApiModelProperty(value = "进度状态")
@TableField("process_status")
private String processStatus;
@ApiModelProperty(value = "物流单编号")
@TableField("tracking_no")
private String trackingNo;
@ApiModelProperty(value = "父订单编号")
@TableField("parent_order_id")
private Long parentOrderId;
@ApiModelProperty(value = "图片路径")
@TableField("img_url")
private String imgUrl;
@TableField(exist = false)
private List<OrderDetail> orderDetailList;
@TableField(exist = false)
private String wareId;
@ApiModelProperty(value = "地区")
@TableField("province_id")
private Long provinceId;
@ApiModelProperty(value = "促销金额")
@TableField("activity_reduce_amount")
private BigDecimal activityReduceAmount;
@ApiModelProperty(value = "优惠券")
@TableField("coupon_amount")
private BigDecimal couponAmount;
@ApiModelProperty(value = "原价金额")
@TableField("original_total_amount")
private BigDecimal originalTotalAmount;
@ApiModelProperty(value = "可退款日期(签收后30天)")
@TableField("refundable_time")
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date refundableTime;
@ApiModelProperty(value = "运费")
@TableField("feight_fee")
private BigDecimal feightFee;
@ApiModelProperty(value = "操作时间")
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
@TableField("operate_time")
private Date operateTime;
// 计算活动或者优惠劵的金额
@TableField(exist = false)
private List<OrderDetailVo> orderDetailVoList;
@TableField(exist = false)
private String orderStatusName;
@TableField(exist = false)
private CouponInfo couponInfo;
// 计算总价格
public void sumTotalAmount(){
BigDecimal totalAmount = new BigDecimal("0");
BigDecimal originalTotalAmount = new BigDecimal("0");
BigDecimal couponAmount = new BigDecimal("0");
// 减去优惠劵
if(null != couponInfo) {
couponAmount = couponAmount.add(couponInfo.getReduceAmount());
totalAmount = totalAmount.subtract(couponInfo.getReduceAmount());
}
// 减去活动
if(null != this.getActivityReduceAmount()) {
totalAmount = totalAmount.subtract(this.getActivityReduceAmount());
}
// 计算最后
for (OrderDetail orderDetail : orderDetailList) {
BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
originalTotalAmount = originalTotalAmount.add(skuTotalAmount);
totalAmount = totalAmount.add(skuTotalAmount);
}
this.setTotalAmount(totalAmount);
this.setOriginalTotalAmount(originalTotalAmount);
this.setCouponAmount(couponAmount);
}
/**
* 获取促销优惠总金额
* @param orderInfo
* @return
*/
public BigDecimal getActivityReduceAmount(OrderInfo orderInfo) {
//促销优惠金额
BigDecimal activityReduceAmount = new BigDecimal("0");
List<OrderDetailVo> orderDetailVoList = orderInfo.getOrderDetailVoList();
if(!CollectionUtils.isEmpty(orderDetailVoList)) {
for(OrderDetailVo orderDetailVo : orderDetailVoList) {
ActivityRule activityRule = orderDetailVo.getActivityRule();
if(null != activityRule) {
activityReduceAmount = activityReduceAmount.add(activityRule.getReduceAmount());
}
}
}
return activityReduceAmount;
}
/**
* 计算购物项分摊的优惠减少金额
* 打折:按折扣分担
* 现金:按比例分摊
* @param orderInfo
* @return
*/
public Map<String, BigDecimal> computeOrderDetailPayAmount(OrderInfo orderInfo) {
Map<String, BigDecimal> skuIdToReduceAmountMap = new HashMap<>();
// 获取到订单明细
List<OrderDetailVo> orderDetailVoList = orderInfo.getOrderDetailVoList();
if (!CollectionUtils.isEmpty(orderDetailVoList)) {
for (OrderDetailVo orderDetailVo : orderDetailVoList) {
// 获取到活动的规则
ActivityRule activityRule = orderDetailVo.getActivityRule();
List<OrderDetail> orderDetailList = orderDetailVo.getOrderDetailList();
if (null != activityRule) {
// key = activity:skuId
//优惠金额, 按比例分摊
BigDecimal reduceAmount = activityRule.getReduceAmount();
if (orderDetailList.size() == 1) {
// 记录活动的减少的金额
skuIdToReduceAmountMap.put("activity:" + orderDetailList.get(0).getSkuId(), reduceAmount);
} else {
// 总金额
BigDecimal originalTotalAmount = new BigDecimal(0);
for (OrderDetail orderDetail : orderDetailList) {
BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
originalTotalAmount = originalTotalAmount.add(skuTotalAmount);
}
// 记录除最后一项是所有分摊金额, 最后一项 = 总的 - skuPartReduceAmount
// 三项 100 一项 33.33 二项 33.33 第三项 100-66.66 = 33.34
BigDecimal skuPartReduceAmount = new BigDecimal(0);
// 促销活动对应的是满减!
if (activityRule.getActivityType().equals(ActivityType.FULL_REDUCTION.name())) {
for (int i = 0, len = orderDetailList.size(); i < len; i++) {
OrderDetail orderDetail = orderDetailList.get(i);
// 最后一项前面一项应该如何做
if (i < len - 1) {
BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
//sku分摊金额 skuTotalAmount/originalTotalAmount * 优惠的金额
BigDecimal skuReduceAmount = skuTotalAmount.divide(originalTotalAmount, 2, RoundingMode.HALF_UP).multiply(reduceAmount);
skuIdToReduceAmountMap.put("activity:" + orderDetail.getSkuId(), skuReduceAmount);
skuPartReduceAmount = skuPartReduceAmount.add(skuReduceAmount);
} else {
// 最后一项
BigDecimal skuReduceAmount = reduceAmount.subtract(skuPartReduceAmount);
skuIdToReduceAmountMap.put("activity:" + orderDetail.getSkuId(), skuReduceAmount);
}
}
} else {
// 满量打折
for (int i = 0, len = orderDetailList.size(); i < len; i++) {
OrderDetail orderDetail = orderDetailList.get(i);
if (i < len - 1) {
BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
//sku分摊金额
BigDecimal skuDiscountTotalAmount = skuTotalAmount.multiply(activityRule.getBenefitDiscount().divide(new BigDecimal("10")));
BigDecimal skuReduceAmount = skuTotalAmount.subtract(skuDiscountTotalAmount);
skuIdToReduceAmountMap.put("activity:" + orderDetail.getSkuId(), skuReduceAmount);
skuPartReduceAmount = skuPartReduceAmount.add(skuReduceAmount);
} else {
BigDecimal skuReduceAmount = reduceAmount.subtract(skuPartReduceAmount);
skuIdToReduceAmountMap.put("activity:" + orderDetail.getSkuId(), skuReduceAmount);
}
}
}
}
}
}
}
// 计算优惠券
CouponInfo couponInfo = orderInfo.getCouponInfo();
if (null != couponInfo) {
//sku对应的订单明细
Map<Long, OrderDetail> skuIdToOrderDetailMap = new HashMap<>();
for (OrderDetail orderDetail : orderInfo.getOrderDetailList()) {
skuIdToOrderDetailMap.put(orderDetail.getSkuId(), orderDetail);
}
// 优惠券对应的skuId列表
List<Long> skuIdList = couponInfo.getSkuIdList();
// 优惠券优惠总金额
BigDecimal reduceAmount = couponInfo.getReduceAmount();
if (skuIdList.size() == 1) {
// sku总的优惠金额 = 优惠券 key = "coupon:skuId"
skuIdToReduceAmountMap.put("coupon:" + skuIdToOrderDetailMap.get(skuIdList.get(0)).getSkuId(), reduceAmount);
} else {
//总金额
BigDecimal originalTotalAmount = new BigDecimal(0);
for (Long skuId : skuIdList) {
OrderDetail orderDetail = skuIdToOrderDetailMap.get(skuId);
BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
originalTotalAmount = originalTotalAmount.add(skuTotalAmount);
}
// 记录除最后一项是所有分摊金额, 最后一项 = 总的 - skuPartReduceAmount
BigDecimal skuPartReduceAmount = new BigDecimal(0);
// 购物券类型 1 现金券 2 折扣券 3 满减券 4 满件打折券
if (couponInfo.getCouponType().equals(CouponType.CASH.name()) || couponInfo.getCouponType().equals(CouponType.FULL_REDUCTION.name())) {
for (int i = 0, len = skuIdList.size(); i < len; i++) {
OrderDetail orderDetail = skuIdToOrderDetailMap.get(skuIdList.get(i));
if (i < len - 1) {
BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
//sku分摊金额
BigDecimal skuReduceAmount = skuTotalAmount.divide(originalTotalAmount, 2, RoundingMode.HALF_UP).multiply(reduceAmount);
skuIdToReduceAmountMap.put("coupon:" + orderDetail.getSkuId(), skuReduceAmount);
skuPartReduceAmount = skuPartReduceAmount.add(skuReduceAmount);
} else {
BigDecimal skuReduceAmount = reduceAmount.subtract(skuPartReduceAmount);
skuIdToReduceAmountMap.put("coupon:" + orderDetail.getSkuId(), skuReduceAmount);
}
}
} else {
// 对应的2,4
for (int i = 0, len = skuIdList.size(); i < len; i++) {
OrderDetail orderDetail = skuIdToOrderDetailMap.get(skuIdList.get(i));
if (i < len - 1) {
BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
BigDecimal skuDiscountTotalAmount = skuTotalAmount.multiply(couponInfo.getBenefitDiscount().divide(new BigDecimal("10")));
BigDecimal skuReduceAmount = skuTotalAmount.subtract(skuDiscountTotalAmount);
//sku分摊金额
skuIdToReduceAmountMap.put("coupon:" + orderDetail.getSkuId(), skuReduceAmount);
skuPartReduceAmount = skuPartReduceAmount.add(skuReduceAmount);
} else {
BigDecimal skuReduceAmount = reduceAmount.subtract(skuPartReduceAmount);
skuIdToReduceAmountMap.put("coupon:" + orderDetail.getSkuId(), skuReduceAmount);
}
}
}
}
}
return skuIdToReduceAmountMap;
}
}
添加mapper
package com.atguigu.gmall.order.mapper;
@Mapper
public interface OrderInfoMapper extends BaseMapper<OrderInfo> {
}
package com.atguigu.gmall.order.mapper;
@Mapper
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
}
添加接口OrderService :
package com.atguigu.gmall.order.service;
public interface OrderService extends IService<OrderInfo> {
/**
* 保存订单
* @param orderInfo
* @return
*/
Long saveOrderInfo(OrderInfo orderInfo);
}
实现类:
package com.atguigu.gmall.order.service.impl;
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {
@Autowired
private OrderInfoMapper orderInfoMapper;
@Autowired
private OrderDetailMapper orderDetailMapper;
@Override
@Transactional
public Long saveOrderInfo(OrderInfo orderInfo) {
//调用里面的方法获取总金额
orderInfo.sumTotalAmount();
//订单状态
orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
//付款方式 在线支付写死了
orderInfo.setPaymentWay(PaymentWay.ONLINE.name());
String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000);
//订单交易号
orderInfo.setOutTradeNo(outTradeNo);
//创建时间,不写也没事数据库自动添加
orderInfo.setCreateTime(new Date());
// 失效时间,定义为1天
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 1);
orderInfo.setExpireTime(calendar.getTime());
//进度状态
orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
//订单描述
// 获取订单明细
List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
StringBuffer tradeBody = new StringBuffer();
for (OrderDetail orderDetail : orderDetailList) {
tradeBody.append(orderDetail.getSkuName()+" ");
}
//如果订单描述长度大于100进行截取
if (tradeBody.toString().length()>100){
orderInfo.setTradeBody(tradeBody.toString().substring(0,100));
}else {
orderInfo.setTradeBody(tradeBody.toString());
}
//保存订单
orderInfoMapper.insert(orderInfo);
for (OrderDetail orderDetail : orderDetailList) {
//设置订单id
orderDetail.setOrderId(orderInfo.getId());
//保存订单明细
orderDetailMapper.insert(orderDetail);
}
return orderInfo.getId();
}
}
继续编写控制器:在OrderApiController:
@Autowired
private OrderService orderService;
/**
* 提交订单
* @param orderInfo
* @param request
* @return
*/
@PostMapping("auth/submitOrder")
public Result submitOrder(@RequestBody OrderInfo orderInfo, HttpServletRequest request) {
// 获取到用户Id
String userId = AuthContextHolder.getUserId(request);
orderInfo.setUserId(Long.parseLong(userId));
// 验证通过,保存订单!
Long orderId = orderService.saveOrderInfo(orderInfo);
return Result.ok(orderId);
}
订单表多了一条数据: