SpringBoot构建电商基础秒杀项目练习(四)

交易

OrderModel

public class OrderModel {
    //交易号不用Integer类型
    //有明确的属性
    private String id;
    //购买用户id
    private Integer userId;
    //购买商品id
    private Integer itemId;
    //购买商品单价
    private BigDecimal itemPrice;
    //购买数量
    private Integer amount;
    //购买金额
    private BigDecimal orderPrice;
    ...
    }

OrderDO

myabtis-generator 中添加代码

<table tableName="order_info" domainObjectName="OrderDO"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false"></table>
               <table tableName="sequence_info" domainObjectName="SequenceDO"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false"></table>

SequenceDOMapper

增加方法完成订单号中间6位自增

SequenceDO getSequenceByName(String name);

xml文件中for update 锁住

 <select id="getSequenceByName" parameterType="java.lang.String" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from sequence_info
    where name = #{name,jdbcType=VARCHAR} for update
  </select>

OrderService & OrderServiceImpl

public interface OrderService {
    OrderModel createOrder(Integer userId, Integer itemId,  Integer amount) throws BusinessException;

}
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private ValidatorImpl validator;

    @Autowired
    private ItemDOMapper itemDOMapper;

    @Autowired
    private ItemStockDOMapper itemStockDOMapper;

    @Autowired
    private ItemServiceImpl itemService;

    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private OrderDOMapper orderDOMapper;

    @Autowired
    private SequenceDOMapper sequenceDOMapper;


    @Override
    @Transactional

    public OrderModel createOrder(Integer userId, Integer itemId, Integer amount) throws BusinessException {

        //校验下单状态,下单的商品是否存在,用户是否合法,购买数量是否正确
        ItemModel itemModel = itemService.getItemById(itemId);
        if (itemId == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATTION_ERROR, "商品信息不存在");
        }

        UserModel userModel = userService.getUserById(userId);
        if (userModel == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATTION_ERROR, "用户信息不存在");
        }

        if (amount <= 0 || amount > 99) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATTION_ERROR, "数量信息不正确");
        }

        //落单减库存
        boolean result = itemService.decreaseStock(itemId, amount);
        if (!result) {
            throw new BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);
        }

        //订单入库
        OrderModel orderModel = new OrderModel();
        orderModel.setUserId(userId);
        orderModel.setItemId(itemId);
        orderModel.setAmount(amount);

        //生成交易流水号,(订单号)
        orderModel.setId(generateOrderNo());
        OrderDO orderDO = convertFromOrderModel(orderModel);
        orderDOMapper.insertSelective(orderDO);

        //加上商品的销量
        itemService.increaseSales(itemId, amount);

        return orderModel;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)//不与创建订单在一个事务
    private String generateOrderNo() {

        //订单号为16位
        StringBuilder stringBuilder = new StringBuilder();
        // 前 8 位为时间信息,年月日 (方便管理  删除)
        LocalDateTime now = LocalDateTime.now();
        String nowDate = now.format(DateTimeFormatter.ISO_DATE).replace("-", "");
        stringBuilder.append(nowDate);
        //中间 6 位为自增序列 (确保订单号唯一)
        int sequence = 0;
        SequenceDO sequenceDO = sequenceDOMapper.getSequenceByName("order_info");
        sequence = sequenceDO.getCurrentValue();

        sequenceDO.setCurrentValue(sequenceDO.getCurrentValue() + sequenceDO.getStep());
        sequenceDOMapper.updateByPrimaryKeySelective(sequenceDO);
        //拼接构成6位
        String sequenceStr = String.valueOf(sequence);
        for (int i = 0; i < 6 - sequenceStr.length(); i++) {
            stringBuilder.append(0);
        }
        stringBuilder.append(sequenceStr);
        // 最后 2 位为分库分表位
        stringBuilder.append("00");

        return stringBuilder.toString();
    }

    private OrderDO convertFromOrderModel(OrderModel orderModel) {
        if (orderModel == null) {
            return null;
        }

        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderModel, orderDO);
        orderDO.setItemPrice(orderModel.getItemPrice().doubleValue());
        orderDO.setOrderPrice(orderModel.getOrderPrice().doubleValue());

        return orderDO;
      }
   }     

这里讲解了下单减库存和交易减库存的优缺点,根据情况选择以及item 和itenStock分开建表的好处。

下单完成后,库存 -1,销量+1;

ItemStockDOMapper添加decreaseStock 减库存,increaseSales加销量方法

 int decreaseStock(@Param("itemId")Integer itemId, @Param("amount")  Integer amount);
 void increaseSales(Integer itemId, Integer amount) throws BusinessException;

减库存可以先查出库存再进行修改操作,视频里提出在ItemStockDOMapper.xml中添加sql语句一次操作完成,生成订单时即完成。

<update id="decreaseStock">
    update item_stock
    set stock = stock - #{amount}
    where item_id = #{itemId} and stock >= #{amount}
  </update>

OrderController

下单前先判断登录状态,这里使用的跟UserController中一样的方式通过session判断,但要注意两个controller中session设置的key值保持一致(“IS_LOGIN”)。

@Controller("order")
@RequestMapping("/order")
@CrossOrigin(allowCredentials = "true", allowedHeaders = "*")

public class OrderController extends  BaseController{

    @Autowired
    private OrderService orderService;
    @Autowired
    private HttpServletRequest httpServletRequest;

    @RequestMapping(value = "/createorder", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
    @ResponseBody
    public CommonReturnType createOrder(@RequestParam(name="itemId") Integer itemId,
                                        @RequestParam(name="amount") Integer amount)
            throws BusinessException {

        Boolean isLogin = (Boolean)httpServletRequest.getSession().getAttribute("IS_LOGIN");
        if(isLogin == null || !isLogin.booleanValue()){
            throw new BusinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登录,不能下单");
        }

        UserModel userModel = (UserModel)httpServletRequest.getSession().getAttribute("LOGIN_USER");

        OrderModel orderModel = orderService.createOrder(userModel.getId(), itemId, amount);

        return CommonReturnType.create(null);
    }
}

秒杀

PromoModel

pom.xml 中引入joda

<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
			<version>2.9.1</version>
</dependency>
public class PromoModel {
    private Integer id;
    // 秒杀活动状态 1: 还未开始 2: 进行中 3: 已结束
    private Integer status;
    //秒杀活动名称
    private String promoName;
    //秒杀开始时间
    private DateTime startDate;
    //秒杀结束时间
    private DateTime endDate;
    //秒杀活动适用商品
    private Integer itemId;
    //秒杀商品价格
    private BigDecimal promoItemPrice;
    
    ...
    }

PromoDO

myabtis-generator 中添加代码

<table tableName="promo" domainObjectName="PromoDO"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false"></table>

PromoDOMapper 增加 selectByItemId方法及实现

PromoDO selectByItemId(Integer itemId);
<select id="selectByItemId" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from promo
    where item_id = #{itemId,jdbcType=INTEGER}
 </select>

ItemVO增加秒杀的属性

// 记录商品是否在秒杀活动中 0:没有秒杀活动 1:待开始 2:进行中
    private Integer promoStatus;
    private BigDecimal promoPrice;
    private Integer promoId;
    private String startDate;

PromoService & PromoServiceImpl

public interface PromoService {
//根据itemId 获取即将进行的或正在进行的秒杀活动
    PromoModel getPromoByItemId(Integer itemId);
}

@Service
public class PromoServiceImpl implements PromoService {
    @Autowired
    private PromoDOMapper promoDOMapper;

    @Override
    public PromoModel getPromoByItemId(Integer itemId) {

        //获取对应的活动商品信息
        PromoDO promoDO = promoDOMapper.selectByItemId(itemId);
        PromoModel promoModel = convertFromDataObject(promoDO);

        if(promoDOMapper == null){
            return null;
        }
        if(promoModel.getStartDate().isAfterNow()){
            promoModel.setStatus(1);
        }else if(promoModel.getEndDate().isBeforeNow()){
            promoModel.setStatus(3);
        }else{
            promoModel.setStatus(2);
        }

        return promoModel;
    }
    //dataObject->model
    private PromoModel convertFromDataObject(PromoDO promoDO){
        if(promoDO == null){
            return null;
        }

        PromoModel promoModel = new PromoModel();
        BeanUtils.copyProperties(promoDO, promoModel);
        promoModel.setPromoItemPrice(new BigDecimal(promoDO.getPromoItemPrice()));
        promoModel.setStartDate(new DateTime(promoDO.getStartDate()));
        promoModel.setEndDate(new DateTime(promoDO.getEndDate()));

        return promoModel;
    }
}

在ItemModel 里添加

private PromoModel promoModel;

OrderDO 增加字段以及修改对应的mapper

private Integer promoId;

修改 ItemController

private ItemVO convertFromModel(ItemModel itemModel){
        if(itemModel == null){
            return null;
        }

        ItemVO itemVO = new ItemVO();
        BeanUtils.copyProperties(itemModel, itemVO);

        if(itemModel.getPromoModel() != null){
            itemVO.setPromoStatus(itemModel.getPromoModel().getStatus());
            itemVO.setPromoId(itemModel.getPromoModel().getId());
            itemVO.setStartDate(itemModel.getPromoModel().getStartDate()
                    .toString(DateTimeFormat.forPattern("yyy-MM-dd HH:mm:ss")));
            itemVO.setPromoPrice(itemModel.getPromoModel().getPromoItemPrice());
        }else{
            itemVO.setPromoStatus(0);
        }

        return itemVO;
    }

修改OrderController

@RequestMapping(value = "/createorder", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
    @ResponseBody
    public CommonReturnType createOrder(@RequestParam(name="itemId") Integer itemId,
                                        @RequestParam(name="amount") Integer amount,
                                        @RequestParam(name="promoId", required = false) Integer promoId)
            throws BusinessException {

        Boolean isLogin = (Boolean)httpServletRequest.getSession().getAttribute("LOGIN");
        if(isLogin == null || !isLogin.booleanValue()){
            throw new BusinessException(EmBusinessError.USER_NOT_LOGIN);
        }

        UserModel userModel = (UserModel)httpServletRequest.getSession().getAttribute("LOGIN_USER");

        OrderModel orderModel = orderService.createOrder(userModel.getId(), itemId, promoId, amount);

        return CommonReturnType.create(null);
    }

相关页面的修改

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值