CTRL + ALT + O ( idea 快捷键删除多余的jar包依赖 )
package com.beyond.enums;
/**
* @Description: 支付方式 枚举
*/
public enum PayMethod {
WEIXIN(1,"微信"),
ALIPAY(2,"支付宝");
public final Integer type;
public final String value;
PayMethod(Integer type, String value){
this.type = type;
this.value = value;
}
}
package com.beyond.pojo.bo;
/**
* 用于创建订单的BO对象
*/
public class SubmitOrderBO {
private String userId;
private String itemSpecIds;
private String addressId;
private Integer payMethod;
private String leftMsg;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getItemSpecIds() {
return itemSpecIds;
}
public void setItemSpecIds(String itemSpecIds) {
this.itemSpecIds = itemSpecIds;
}
public String getAddressId() {
return addressId;
}
public void setAddressId(String addressId) {
this.addressId = addressId;
}
public Integer getPayMethod() {
return payMethod;
}
public void setPayMethod(Integer payMethod) {
this.payMethod = payMethod;
}
public String getLeftMsg() {
return leftMsg;
}
public void setLeftMsg(String leftMsg) {
this.leftMsg = leftMsg;
}
@Override
public String toString() {
return "SubmitOrderBO{" +
"userId='" + userId + '\'' +
", itemSpecIds='" + itemSpecIds + '\'' +
", addressId='" + addressId + '\'' +
", payMethod=" + payMethod +
", leftMsg='" + leftMsg + '\'' +
'}';
}
}
package com.beyond.controller;
import com.beyond.enums.PayMethod;
import com.beyond.pojo.bo.SubmitOrderBO;
import com.beyond.service.OrderService;
import com.beyond.utils.BEYONDJSONResult;
import com.beyond.utils.CookieUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Api(value = "与订单相关",tags = {
"订单相关的接口"})
@RestController
@RequestMapping("orders")
public class OrdersController extends BaseController {
@Autowired
private OrderService orderService;
@ApiOperation(value = "用户订单功能",notes = "用户订单功能 ",httpMethod = "POST")
@PostMapping("/create")
public BEYONDJSONResult create(
@RequestBody SubmitOrderBO submitOrderBO, // 该注解表示接收一个json对象
HttpServletRequest request,
HttpServletResponse response
){
if (submitOrderBO.getPayMethod() != PayMethod.WEIXIN.type
&& submitOrderBO.getPayMethod() != PayMethod.ALIPAY.type
){
return BEYONDJSONResult.errorMsg("支付方式不支持");
}
System.out.println(submitOrderBO.toString());
// 1. 创建订单
String orderId = orderService.createOrder(submitOrderBO);
// 2. 创建订单后移除中已结算(已提交)的商品
// TODO 整合redis之后, 完善购物车中已结算商品清除, 并且同步到前端的cookie
CookieUtils.setCookie(request, response, COOKIE_SHOPCART, "",true);
// 3. 向支付中心发送当前订单, 用于保存支付中心的订单
return BEYONDJSONResult.ok(orderId);
}
}
/**
* 根据传人的用户id 和地址id 查找用户的地址信息
* @param userId
* @param addressId
*/
public UserAddress queryUserAddress(String userId,String addressId);
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public UserAddress queryUserAddress(String userId, String addressId) {
UserAddress userAddress = new UserAddress();
userAddress.setUserId(userId);
userAddress.setId(addressId);
return userAddressMapper.selectOne(userAddress);
}
/**
* 根据商品Id 获取商品的规格信息
* @param specId
* @return
*/
public ItemsSpec queryItemSpecById(String specId);
/**
* 根据商品id 获得商品主图
* @param itemId
* @return
*/
public String queryItemMainImgById(String itemId);
/**
* 更新库存
* @param specId
* @param buyCounts
*/
public void decreaseItemSpecStock(String specId, Integer buyCounts);
@Override
public ItemsSpec queryItemSpecById(String specId) {
return itemsSpecMapper.selectByPrimaryKey(specId);
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public String queryItemMainImgById(String itemId) {
ItemsImg itemsImg = new ItemsImg();
itemsImg.setItemId(itemId);
itemsImg.setIsMain(YesOrNo.YES.type);
ItemsImg result = itemsImgMapper.selectOne(itemsImg);
return result != null ? result.getUrl() : "";
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void decreaseItemSpecStock(String specId, Integer buyCounts) {
// synchronized 不推荐使用, 在集群环境下无效, 性能低下
// 不能锁数据库, 也导致数据库性能低下, 且一旦发生故障则无法承担后果
// 可以使用分布式锁 zookeeper redis
// 这里使用对 mapper 的乐观锁实现 避免超卖处理
int result = itemsMapperCustom.decreaseItemSpecStock(specId, buyCounts);
if (result != 1){
throw new RuntimeException("订单创建失败, 库存不足!");
}
package com.beyond.enums;
/**
* @Description : 订单状态 枚举
*/
public enum OrderStatusEnum {
WAIT_PAY(10,"待付款"),
WAIT_DELIVER(20,"已付款, 待发货"),
WAIT_RECEIVE(30,"已发货, 待收货"),
SUCCESS(40,"交易成功"),
CLOSE(50,"交易关闭");
public final Integer type;
public final String value;
OrderStatusEnum(Integer type, String value){
this.type = type;
this.value = value;
}
}
<!-- 使用 乐观锁机制实现并发超卖处理-->
<update id="decreaseItemSpecStock" >
update
items_spec
set stock = stock - #{
pendingCounts}
where
id = #{
specId} and stock >= #{
pendingCounts}
</update>
public int decreaseItemSpecStock(@Param("specId") String specId,
@Param("pendingCounts") int pendingCounts);
package com.beyond.service;
import com.beyond.pojo.bo.SubmitOrderBO;
public interface OrderService {
public String createOrder(SubmitOrderBO submitOrderBO);
}
package com.beyond.service.impl;
import com.beyond.enums.OrderStatusEnum;
import com.beyond.enums.YesOrNo;
import com.beyond.mapper.OrderItemsMapper;
import com.beyond.mapper.OrderStatusMapper;
import com.beyond.mapper.OrdersMapper;
import com.beyond.pojo.*;
import com.beyond.pojo.bo.SubmitOrderBO;
import com.beyond.service.AddressService;
import com.beyond.service.ItemService;
import com.beyond.service.OrderService;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@SuppressWarnings("ALL")
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrdersMapper ordersMapper;
@Autowired
private AddressService addressService;
@Autowired
private Sid sid;
@Autowired
private ItemService itemService;
@Autowired
private OrderItemsMapper orderItemsMapper;
@Autowired
private OrderStatusMapper orderStatusMapper;
@Transactional(propagation = Propagation.REQUIRED)
@Override
public String createOrder(SubmitOrderBO submitOrderBO) {
String userId = submitOrderBO.getUserId();
String addressId = submitOrderBO.getAddressId();
String itemSpecIds = submitOrderBO.getItemSpecIds();
Integer payMethod = submitOrderBO.getPayMethod();
String leftMsg = submitOrderBO.getLeftMsg();
// 包邮费用设置为0
Integer postAmount = 0;
String orderId = sid.nextShort();
// 1. 新订单数据保存
Orders newOrder = new Orders();
newOrder.setId(orderId);
newOrder.setUserId(userId);
UserAddress userAddress = addressService.queryUserAddress(userId, addressId);
newOrder.setReceiverName(userAddress.getReceiver());
newOrder.setReceiverMobile(userAddress.getMobile());
newOrder.setReceiverAddress(userAddress.getProvince()+" "
+userAddress.getCity()+" "
+userAddress.getDistrict()+" "
+userAddress.getDetail() );
newOrder.setPostAmount(postAmount);
newOrder.setLeftMsg(leftMsg);
newOrder.setPayMethod(payMethod);
newOrder.setIsComment(YesOrNo.NO.type);
newOrder.setIsDelete(YesOrNo.NO.type);
newOrder.setCreatedTime(new Date());
newOrder.setUpdatedTime(new Date());
// 2. 循环根据itemSpecIds保存订单商品信息表
String[] itemSpecIdArr = itemSpecIds.split(",");
Integer totalAmount = 0; // 商品的原价累计
Integer realPayAmount = 0; // 商品优惠后的价格统计
for (String itemSpecId : itemSpecIdArr){
// TODO 整合 redis后, 商品购买的数量重新从redis的购物车中获取
int buyCounts = 1;
// 2.1 根据规格id, 查询规格的具体信息, 主要获取价格
ItemsSpec itemsSpec = itemService.queryItemSpecById(itemSpecId);
totalAmount += itemsSpec.getPriceNormal() * buyCounts;
realPayAmount += itemsSpec.getPriceDiscount() * buyCounts;
// 2.2 根据商品id 获得商品信息和商品图片
String itemId = itemsSpec.getItemId();
Items items = itemService.queryItemById(itemId);
String imgUrl = itemService.queryItemMainImgById(itemId);
// 2.3 循环保存子订单数据到数据库
OrderItems subOrderItem = new OrderItems();
String subOrderId = sid.nextShort();
subOrderItem.setId(subOrderId);
subOrderItem.setOrderId(orderId);
subOrderItem.setItemId(itemId);
subOrderItem.setItemName(items.getItemName());
subOrderItem.setItemImg(imgUrl);
subOrderItem.setBuyCounts(buyCounts);
subOrderItem.setItemSpecId(itemSpecId);
subOrderItem.setItemSpecName(itemsSpec.getName());
subOrderItem.setPrice(itemsSpec.getPriceDiscount());
orderItemsMapper.insert(subOrderItem);
// 2.4 在用户购买后应该匹配好库存, 扣除库存
itemService.decreaseItemSpecStock(itemSpecId,buyCounts);
}
newOrder.setTotalAmount(totalAmount);
newOrder.setRealPayAmount(realPayAmount);
ordersMapper.insert(newOrder);
// 3. 保存订单状态表
OrderStatus waitPayOrderStatus = new OrderStatus();
waitPayOrderStatus.setOrderId(orderId);
waitPayOrderStatus.setOrderStatus(OrderStatusEnum.WAIT_PAY.type);
waitPayOrderStatus.setCreatedTime(new Date());
orderStatusMapper.insert(waitPayOrderStatus);
return orderId;
}
}