活动模型与商品模型结合

该文描述了一个Java应用中实现商品秒杀活动的步骤,包括创建PromoService接口、定义Mapper和SQL查询、数据库字段更新、模型转换、服务实现、前端展示信息修改以及订单处理,确保在商品详情页面显示秒杀状态和时间,并支持用户下单参与秒杀活动。
摘要由CSDN通过智能技术生成

1.创建PromoService接口


public interface PromoService {
      PromoModel getPromoByItemId(Integer itemId);
}

2.在PromoDOMapper中可定义方法

 PromoDO selectByItemId(Integer itemId);

3.在PromoDOMapper.xml中添加sql语句

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

4.在数据库promo中添加字段end_date 相应的PromoModel和对应的xml文件中需要手动修改 

  还有PromoDO

在PromoModel中添加private Integer status;来判断秒杀状态 数据库中不用写入

5.创建实现接口的PromoServiceImpl

@Service
public class PromoServiceImpl implements PromoService {

    @Autowired
    private PromoDOMapper promoDOMapper;
    @Override
    public PromoModel getPromoByItemId(Integer itemId) {
        //获取对应商品的秒杀活动信息
        PromoDO promoDO = promoDOMapper.selectByItemId(itemId);

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

        //判断当前时间 是否 秒杀活动即将开始或者正在进行
        DateTime now = new DateTime();
        //开始时间比现在还要后面 活动未开始
        if(promoModel.getStartDate().isAfterNow()){
            promoModel.setStatus(1);
            //开始时间比现在还要前面 活动已结束
        }else if(promoModel.getEndDate().isBeforeNow()){
            promoModel.setStatus(3);
            //其他的情况在录入数据中
        }else{
            promoModel.setStatus(2);
        }
        return promoModel;
    }
    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;
    }
}

6.ItemModel

    //使用聚合模型,如果promoModel不为空,则表示其拥有还未结束的秒杀活动
    private PromoModel promoModel;

    public PromoModel getPromoModel() {
        return promoModel;
    }

    public void setPromoModel(PromoModel promoModel) {
        this.promoModel = promoModel;
    }

7.ItemServiceImpl

 @Override
    public ItemModel getItemById(Integer id) {
        ItemDO itemDO = itemDOMapper.selectByPrimaryKey(id);
        if(itemDO == null){
            return null;
        }
        //操作获得库存数量
        ItemStockDO itemStockDO=itemStockDOMapper.selectByItemId(itemDO.getId());



        //将dataobject->model
        ItemModel itemModel = convertModelFromDataObject(itemDO,itemStockDO);


        //获取活动商品信息
       PromoModel promoModel= promoService.getPromoByItemId(itemModel.getId());
       //=null 没有秒杀活动 !=有秒杀活动
       if(promoModel != null && promoModel.getStatus().intValue()!=3){
           itemModel.setPromoModel(promoModel);
       }
        return itemModel;
    }

8.ItemVO 前端展示信息添加

    //记录商品是否在秒杀活动中 以及秒杀状态 0表示没有秒杀活动 1表示秒杀活动待开始 2表示秒杀活动进行中
    private Integer promoStatus;

    //秒杀活动价格
    private BigDecimal promoPrice;

    //秒杀活动ID
    private Integer promoId;

    //秒杀活动开始时间 用来做倒计时用
    private DateTime startDate;

    //get set 方法

9.ItemController

 //商品详情页浏览
    @RequestMapping(value = "/get", method = {RequestMethod.GET})
    @ResponseBody
    public CommonReturnType getItem(@RequestParam(name = "id") Integer id ){
          ItemModel itemModel=itemService.getItemById(id);

          ItemVO itemVO = convertVOFromModel(itemModel);

          return CommonReturnType.create(itemVO);
    }
    private ItemVO convertVOFromModel(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());
                itemVO.setPromoPrice(itemModel.getPromoModel().getPromoItemPrice());
            }else{
                itemVO.setPromoStatus(0);
            }
            return itemVO;
        }

10.修改ItemVO中的开始时间类型为String

 //秒杀活动开始时间 用来做倒计时用
    private String startDate;

11.修改ItemController中关于开始时间的语句

    private ItemVO convertVOFromModel(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("yyyy-MM-dd HH:mm:ss")));
                itemVO.setPromoPrice(itemModel.getPromoModel().getPromoItemPrice());
            }else{
                itemVO.setPromoStatus(0);
            }
            return itemVO;
        }

12.修改OrderModel

 //订单号 有属性
    private String id;

    //购买用户的id
    private Integer userId;

    //购买的商品id
    private Integer itemId;

    //若非空,则表示是以秒杀商品的方式下单
    private Integer promoId;

    //购买商品的单价,若promoId非空,则表示秒杀商品价格
    private BigDecimal itemPrice;

    //购买数量
    private Integer amount;

    //购买金额若promoId非空,则表示秒杀商品价格
    private BigDecimal orderPrice;

13.在order_info表中添加字段promo_id

    同时修改OrderDO

 private Integer promoId;

修改OrderDOMapper.xml

14.修改OrderService


public interface OrderService {
    //使用了1.通过前端url上传过来秒杀活动id,然后下单接口内校验对应id是否属于对应商品且活动已开始
    //2.直接再下单接口内判断对应的商品是否存在秒杀活动,若存在进行中的则以秒杀价格下单
    OrderModel createOrder(Integer userId, Integer itemId,Integer promoId, Integer amount) throws BusinessException;


}

15.OrderServiceImpl

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private SequenceDOMapper sequenceDOMapper;

    @Autowired
    private ItemService itemService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderDOMapper orderDOMapper;

    @Override
    //保证创建订单在同一个事务当中
    @Transactional
    public OrderModel createOrder(Integer userId, Integer itemId,Integer promoId, Integer amount) throws BusinessException {
        //1.校验下单状态,下单的商品是否存在,用户是否合法,购买数量是否正确
        ItemModel itemModel = itemService.getItemById(itemId);
        if(itemModel == null){
            throw  new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"商品信息不存在");
        }

        UserModel userModel =userService.getUserById(userId);
        if(userModel == null){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"用户信息不存在");
        }
        //下单数量假设为不能小于0 不能大于99
        if(amount <=0 || amount >99){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"购买的数量信息不正确");
        }

        //校验活动信息
        if(promoId !=1){
            //(1)校验对应活动是否存在这个对应的商品
            if(promoId.intValue()!=itemModel.getPromoModel().getId()){
                throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"活动信息不正确");
                //(2)校验活动是否正在进行中
            }else if(itemModel.getPromoModel().getStatus().intValue()!=2){
                throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"活动信息不正确");
            }
        }

 // 2.落单减库存:在调用订单的createorder下单之前,先把amount数量的库存锁定给这个用户使用,若库存不够就为下单失败。下单成功则锁定库存的操作必定成功
 //  支付减库存(未使用)
           boolean result = itemService.decreaseStock(itemId,amount);
           if(!result){
               throw new BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);
           }

        //3.订单入库
            OrderModel orderModel = new OrderModel();
            orderModel.setUserId(userId);
            orderModel.setItemId(itemId);
            orderModel.setAmount(amount);
            if(promoId != null){
                orderModel.setItemPrice(itemModel.getPromoModel().getPromoItemPrice());
            }else{
                orderModel.setItemPrice(itemModel.getPrice());
            }
            orderModel.setPromoId(promoId);
            orderModel.setOrderPrice(orderModel.getItemPrice().multiply(new BigDecimal(amount)));
           //生成交易流水号--订单号
            orderModel.setId(generateOrderNo());
            OrderDO orderDO = convertFromOrderModel(orderModel);
           orderDOMapper.insertSelective(orderDO);

           //加上商品销量
        itemService.increaseSales(itemId,amount);
        //4.返回前端
        return orderModel;
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private String generateOrderNo(){
        //订单号有16位
        StringBuilder stringBuilder = new StringBuilder();
        //前八位为时间信息 年月日
        //获取今天日期
        LocalDateTime now = LocalDateTime.now();
        String nowDate= now.format(DateTimeFormatter.ISO_DATE).replace("-","");
        stringBuilder.append(nowDate);

        //中间六位为自增序列
        //获取当前sequence
        int sequence = 0;
        SequenceDO sequenceDO = sequenceDOMapper.getSequenceByName("order_info");

        sequence =sequenceDO.getCurrentValue();
        sequenceDO.setCurrentValue(sequenceDO.getCurrentValue() + sequenceDO.getStep());
        sequenceDOMapper.updateByPrimaryKeySelective(sequenceDO);

        //拼接对应的sequence 凑够六位
        String sequenceStr = String.valueOf(sequence);
        for(int i =0; i < 6-sequenceStr.length();i++){
            stringBuilder.append(0);
        }
         stringBuilder.append(sequenceStr);

        //最后两位为分库分表为1-99 暂时写死
        stringBuilder.append("00");

        return stringBuilder.toString();
    }

    //将Model转为为一个dataobject的方式
    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;
    }
}

16.OrderController

@Controller("order")
@RequestMapping("/order")
@CrossOrigin(origins = {"*"},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,
                                        @RequestParam(name="promoId",required=false)Integer promoId) 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(), promoId,itemId, amount);

        return CommonReturnType.create(null);
    }

}

17.修改getitem.html界面  商品详情页

<html>
<head>
    <meta charset="UTF-8">
    <link href="static/assets/global/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
    <link href="static/assets/global/css/components.css" rel="stylesheet" type="text/css"/>
    <link href="static/assets/admin/pages/css/login.css" rel="stylesheet" type="text/css"/>
    <script src="static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script>
    <title>Title</title>
</head>
<body class="login">
<div class="content">
    <h3 class="form-title">商品详情</h3>

    <div id="promoStartDateContainer" class="form-group">
        <label style="color: blue" id="promoStatus" class="control-label"></label>
        <div>
            <label style="color: red" class="control-label" id="promoStartDate" />
        </div>
    </div>

    <div class="form-group">
        <label class="control-label">商品名</label>
        <div>
            <label class="control-label" id="title" />
        </div>
    </div>
    <div class="form-group">
        <label class="control-label">商品描述</label>
        <div>
            <label class="control-label" id="description" />
        </div>
    </div>
    <div id="normalPriceContainer" class="form-group">
        <label class="control-label">商品价格</label>
        <div>
            <label class="control-label" id="price" />
        </div>
    </div>
    <div id="promoPriceContainer" class="form-group">
        <label style="color: red" class="control-label">秒杀价格</label>
        <div>
            <label style="color: red" class="control-label" id="promoPrice" />
        </div>
    </div>
    <div class="form-group">
        <label class="control-label">图片</label>
        <div>
            <img style="width: 200px;height: auto" id="imgUrl"/>
        </div>
    </div>
    <div class="form-group">
        <label class="control-label">商品库存</label>
        <div>
            <label class="control-label" id="stock" />
        </div>
    </div>

    <div class="form-group">
        <label class="control-label">商品销量</label>
        <div>
            <label class="control-label" id="sales" />
        </div>
        <div class="form-actions">
            <button class="btn blue" id="createorder" type="submit">
                下单
            </button>
        </div>
    </div>
    </div>
</div>
</body>

<script>
    function getParam(paramName) {
        paramValue = "", isFound = !1;
        if (this.location.search.indexOf("?") == 0 && this.location.search.indexOf("=") > 1) {
            arrSource = unescape(this.location.search).substring(1, this.location.search.length).split("&"), i = 0;
            while (i < arrSource.length && !isFound)
                arrSource[i].indexOf("=") > 0 && arrSource[i].split("=")[0].toLowerCase() == paramName.toLowerCase() && (paramValue = arrSource[i].split("=")[1], isFound = !0), i++
        }
        return paramValue == "" && (paramValue = null), paramValue
    }
    var g_itemVO = {};
    jQuery(document).ready(function () {
        $("#createorder").on("click",function () {
            $.ajax({
                type:"POST",
                contentType:"application/x-www-form-urlencoded",
                url:"http://localhost:8090/order/createorder",
                data:{
                    "itemId":g_itemVO.id,
                    "amount":1,
                    "promoId":g_itemVO.promoId

                },
                //允许跨域请求
                xhrFields:{withCredentials:true},
                success:function (data) {
                    if (data.status=="success") {
                      alert("下单成功");
                      window.location.reload();
                    }else {
                        alert("下单失败,原因为" + data.data.errMsg);
                        if(data.data.errCode == 20003){
                            window.location.href="login.html"
                        }
                    }
                },
                error:function (data) {
                    alert("下单失败,原因为"+data.responseText);
                }
            });
        })
            //获取商品详情
            $.ajax({
                type:"GET",
                contentType:"application/x-www-form-urlencoded",
                url:"http://localhost:8090/item/get",
                data:{
                    "id":getParam("id"),

                },
                //允许跨域请求
                xhrFields:{withCredentials:true},
                success:function (data) {
                    if (data.status=="success") {
                        g_itemVO = data.data;
                        reloadDom();
                        //每隔一秒钟执行一次
                        setInterval(reloadDom,1000)
                    }else {
                        alert("获取信息失败,原因为" + data.data.errMsg);
                    }
                },
                error:function (data) {
                    alert("获取信息失败,原因为"+data.responseText);
                }
            });
        });
    function reloadDom() {
        $("#title").text(g_itemVO.title);
        $("#imgUrl").attr("src", g_itemVO.imgUrl);
        $("#description").text(g_itemVO.description);
        $("#price").text(g_itemVO.price);
        $("#stock").text(g_itemVO.stock);
        $("#sales").text(g_itemVO.sales);
        if(g_itemVO.promoStatus == 1){
            //秒杀活动还未开始
            //倒计时
           var startTime= g_itemVO.startDate.replace(new RegExp("-","gm"),"/");
           startTime = (new Date(startTime)).getTime();
           var nowTime = Date.parse(new Date());
           var delta = (startTime - nowTime)/1000;

           if(delta <= 0){
               //活动开始了
               g_itemVO.promoStatus=2;
               reloadDom();
           }

            $("#promoStartDate").text("秒杀活动将于: "+g_itemVO.startDate+"开始售卖 倒计时:"+delta+"秒");
            $("#promoPrice").text(g_itemVO.promoPrice);
            //秒杀活动没开始时 不能下单
            $("#createorder").attr("disabled",true);
        }else if(g_itemVO.promoStatus == 2){
            //秒杀活动正在进行
            $("#promoStartDate").text("秒杀正在进行中");
            $("#promoPrice").text(g_itemVO.promoPrice);
            //秒杀活动开始时 可以下单
            $("#createorder").attr("disabled",false);

            $("#normalPriceContainer").hide();
        }
    }
</script>
</html>

运行效果图  成功!!!

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值