移动商城第十九篇【提交订单】


tags: 移动商城项目


订单提交预备

当结算完之后会跳转到订单提交页面。首先我们来看一下订单提交页面是怎么样的:

我们需要把用户的地址、商品的信息查询出来在页面上展示!

那么在跳转到确认页面的时候,我们把数据查询出来即可!


    @RequestMapping("/toSubmitOrder.do")
    public String toSubmitOrder(HttpSession session, Model model, HttpServletRequest request,HttpServletResponse response) {

        //查询用户的地址
        TsPtlUser user = (TsPtlUser) session.getAttribute("user");
        List<EbShipAddr> userAddress = addrService.findUserAddress(user.getPtlUserId());

        //查询购物车清单的信息
        List<EbCart> carts = cartService.listCart(request, response);

        //算出购物车总价和商品数量
        int itemNum = 0;
        BigDecimal totalPrice = new BigDecimal(0);
        for (EbCart cart : carts) {
            totalPrice = totalPrice.add(cart.getSku().getSkuPrice().multiply(new BigDecimal(cart.getQuantity())));
            itemNum++;
        }

        model.addAttribute("carts", carts);
        model.addAttribute("totalPrice",totalPrice);
        model.addAttribute("itemNum",itemNum);
        model.addAttribute("userAddress", userAddress);
        return "shop/confirmProductCase";

    }
复制代码

查看订单的数据库表


DROP TABLE EB_ORDER CASCADE CONSTRAINTS;

CREATE TABLE EB_ORDER  (
   ORDER_ID             NUMBER(11)                      NOT NULL,
   PTL_USER_ID          NUMBER(11),
   "USERNAME"           VARCHAR2(100),
   ORDER_NUM            VARCHAR2(80),
   PAYMENT              NUMBER(1),
   PAY_PLATFORM         NUMBER(2),
   DELIVERY             NUMBER(1),
   IS_CONFIRM           NUMBER(1),
   ORDER_SUM            NUMBER(20,2),
   SHIP_FEE             NUMBER(20,2),
   IS_PAID              NUMBER(1),
   ORDER_STATE          NUMBER(2),
   PAYMENT_CASH         NUMBER(1),
   DISTRI_ID            NUMBER(11),
   DELIVERY_METHOD      NUMBER(1),
   PAYMENT_NO           VARCHAR2(30),
   ORDER_TIME           TIMESTAMP,
   PAY_TIME             TIMESTAMP,
   DEPOSIT_TIME         TIMESTAMP,
   SUCCESS_TIME         TIMESTAMP,
   UPDATE_TIME          TIMESTAMP,
   SRV_TYPE             NUMBER(2),
   SELF_COLLECT_SITE    VARCHAR2(200),
   IS_DELETED           NUMBER(1)                      DEFAULT 0,
   IS_DISPLAY           NUMBER(1),
   NOTES                VARCHAR2(400),
   SHIP_NAME            VARCHAR2(80)                    NOT NULL,
   PROVINCE             VARCHAR2(40)                    NOT NULL,
   CITY                 VARCHAR2(40)                    NOT NULL,
   DISTRICT             VARCHAR2(40)                    NOT NULL,
   ZIP_CODE             VARCHAR2(40),
   ADDR                 VARCHAR2(400)                   NOT NULL,
   PHONE                VARCHAR2(60)                    NOT NULL,
   PAYABLE              NUMBER(1),
   COMPANY              VARCHAR2(240),
   CONTENTS             NUMBER(2),
   IS_CALL              NUMBER(1)                      DEFAULT 0,
   DELIVERY_NO          VARCHAR2(300),
   AREA_CODE            VARCHAR2(50),
   AREA_NAME            VARCHAR2(50),
   IS_PRINT             NUMBER(1)                      DEFAULT 0,
   CRM_CALLS_TIME       TIMESTAMP,
   IS_OFFER_RELEASE     NUMBER(1)                      DEFAULT 0,
   JOB_NUM              VARCHAR2(300),
   CONSTRAINT PK_EB_ORDER PRIMARY KEY (ORDER_ID)
);

COMMENT ON TABLE EB_ORDER IS
'订单。包括实体商品和虚拟商品的订单';

COMMENT ON COLUMN EB_ORDER.ORDER_ID IS
'订单主键';

COMMENT ON COLUMN EB_ORDER.PTL_USER_ID IS
'前台用户主键';

COMMENT ON COLUMN EB_ORDER."USERNAME" IS
'冗余前台用户名称,只允许以Email地址注册,不可重复,注册后不可修改。大于0小于等于50个字符,必须包含一个并且只有一个符号@ ;第一个字符不得是@或者. ;不允许出现@.或者.@;结尾不得用户账号:只允许以Email地址注册,不可重复,注册后不可修改';

COMMENT ON COLUMN EB_ORDER.ORDER_NUM IS
'订单号:订单号规则:订单生成日期+6位数,递增. 订单起始编号:111024000001. 后六位数一旦满,则后六位数递增为七位数';

COMMENT ON COLUMN EB_ORDER.PAYMENT IS
'支付方式:1: 在线支付;2: 货到付款;3: 营业厅自取;4:邮局汇款';

COMMENT ON COLUMN EB_ORDER.PAY_PLATFORM IS
'支付平台:1: 工商银行; 2: 建设银行; 3: 招商银行';

COMMENT ON COLUMN EB_ORDER.DELIVERY IS
'送货时间:1: 只工作日送货(双休日,假日不用送); 2: 工作日、双休日、假日均可送货; 3: 只双休日、假日送货(工作日送货)';

COMMENT ON COLUMN EB_ORDER.IS_CONFIRM IS
'送货前电话确认:0: 否; 1: 是';

COMMENT ON COLUMN EB_ORDER.ORDER_SUM IS
'订单总金额:各订单项的售价之和,包括运费等。';

COMMENT ON COLUMN EB_ORDER.SHIP_FEE IS
'运费';

COMMENT ON COLUMN EB_ORDER.IS_PAID IS
'是否已支付:0: 未付款; 1: 已付款';

COMMENT ON COLUMN EB_ORDER.ORDER_STATE IS
'订单状态。参见类EbOrderStateConstants.java';

COMMENT ON COLUMN EB_ORDER.PAYMENT_CASH IS
'货到付款方式:1: 现金;2: POS刷卡; 3: 支票';

COMMENT ON COLUMN EB_ORDER.DISTRI_ID IS
'配送商ID';

COMMENT ON COLUMN EB_ORDER.DELIVERY_METHOD IS
'送货方式:1:快递;2:EMS;3:平邮';

COMMENT ON COLUMN EB_ORDER.PAYMENT_NO IS
'支付号';

COMMENT ON COLUMN EB_ORDER.ORDER_TIME IS
'下单时间';

COMMENT ON COLUMN EB_ORDER.PAY_TIME IS
'付款时间';

COMMENT ON COLUMN EB_ORDER.DEPOSIT_TIME IS
'到帐时间';

COMMENT ON COLUMN EB_ORDER.SUCCESS_TIME IS
'成功时间';

COMMENT ON COLUMN EB_ORDER.SRV_TYPE IS
'业务类型,0:无业务;1:需要写卡;2:需要办理CRM;3:需要写卡和办理CRM';

COMMENT ON COLUMN EB_ORDER.SELF_COLLECT_SITE IS
'商品自提点名称';

COMMENT ON COLUMN EB_ORDER.IS_DELETED IS
'前台用户删除订单标记。1:是;0:否';

COMMENT ON COLUMN EB_ORDER.IS_DISPLAY IS
'前台用户删除订单标记。1:是;0:否';

COMMENT ON COLUMN EB_ORDER.NOTES IS
'备注';

COMMENT ON COLUMN EB_ORDER.SHIP_NAME IS
'收货人姓名';

COMMENT ON COLUMN EB_ORDER.PROVINCE IS
'省份';

COMMENT ON COLUMN EB_ORDER.CITY IS
'城市';

COMMENT ON COLUMN EB_ORDER.DISTRICT IS
'地区';

COMMENT ON COLUMN EB_ORDER.ZIP_CODE IS
'邮编';

COMMENT ON COLUMN EB_ORDER.ADDR IS
'街道地址';

COMMENT ON COLUMN EB_ORDER.PHONE IS
'联系电话';

COMMENT ON COLUMN EB_ORDER.PAYABLE IS
'发票抬头:1: 个人;2: 单位';

COMMENT ON COLUMN EB_ORDER.COMPANY IS
'单位名称';

COMMENT ON COLUMN EB_ORDER.CONTENTS IS
'发票内容:1: 明细;2: 办公用品';

COMMENT ON COLUMN EB_ORDER.IS_CALL IS
'是否外呼过。0:未外呼;1:已外呼';

COMMENT ON COLUMN EB_ORDER.DELIVERY_NO IS
'物流编号。';

COMMENT ON COLUMN EB_ORDER.AREA_CODE IS
'市区代码(冗余自EB_CITY_AREA表)';

COMMENT ON COLUMN EB_ORDER.AREA_NAME IS
'市区名称(冗余自EB_CITY_AREA表)';

COMMENT ON COLUMN EB_ORDER.IS_PRINT IS
'是否需要打印发票。0-不需要打印;1-需要打印;';

COMMENT ON COLUMN EB_ORDER.CRM_CALLS_TIME IS
'crm办理成功或失败的时间';

COMMENT ON COLUMN EB_ORDER.IS_OFFER_RELEASE IS
'是否营销案解约。0-否;1-是;';

COMMENT ON COLUMN EB_ORDER.JOB_NUM IS
'工单号,由crm接口返回';

复制代码

订单明细表:


DROP TABLE EB_ORDER_DETAIL CASCADE CONSTRAINTS;

CREATE TABLE EB_ORDER_DETAIL  (
   ORDER_DETAIL_ID      NUMBER(11)                      NOT NULL,
   ORDER_ID             NUMBER(11),
   ITEM_ID              NUMBER(11),
   ITEM_NAME            VARCHAR2(400),
   ITEM_NO              VARCHAR2(120),
   SKU_ID               NUMBER(11),
   SKU                  VARCHAR2(80),
   SKU_IMG              VARCHAR2(80),
   SKU_NAME             VARCHAR2(500),
   SKU_CAT_TYPE         NUMBER(5),
   SKU_SPEC             VARCHAR2(1000),
   MARKET_PRICE         NUMBER(20,2),
   SKU_DISCOUNT         NUMBER(20,2),
   SKU_PRICE            NUMBER(20,2),
   OFFER_GROUP_ID       NUMBER(11),
   OFFER_GROUP_NAME     VARCHAR2(200),
   OFFER_TYPE           NUMBER(2),
   SHORT_NAME           VARCHAR2(80),
   OFFER_ID             NUMBER(11),
   OFFER_NAME           VARCHAR2(800),
   OFFER_NO             VARCHAR2(120),
   SHORT_NAME2          VARCHAR2(50),
   OFFER_TERM           NUMBER(2),
   COMMIT_MONTHLY       NUMBER(20,2),
   PREPAID              NUMBER(20,2),
   PERIOD               NUMBER(2),
   REFUND_MONTHLY       NUMBER(20,2),
   REFUND_1ST_MONTH     NUMBER(20,2),
   REFUND_LAST_MONTH    NUMBER(20,2),
   ORDER_DETAIL_TYPE    NUMBER(2),
   MERCHANT_ID          NUMBER(11),
   QUANTITY             NUMBER(5),
   PRICE                NUMBER(20,2),
   SERIESCODE           VARCHAR2(3000),
   OFFER_GROUP_NO       VARCHAR2(300),
   PROMO_TYPE           NUMBER(4),
   COND_ID              NUMBER(8),
   CONSTRAINT PK_EB_ORDER_DETAIL PRIMARY KEY (ORDER_DETAIL_ID)
);

COMMENT ON TABLE EB_ORDER_DETAIL IS
'3-10是商品的冗余数据
11-26是营销案的冗余数据

营销案的时候,根据SKU存多条,每条SKU的营销案信息一致


备注:
当订单中包含offer,offer里包含sku的时候,
在保存offer内的sku信息时,会冗余offer信息到该条记录中,便于订单的查询。';

COMMENT ON COLUMN EB_ORDER_DETAIL.ORDER_ID IS
'订单主键';

COMMENT ON COLUMN EB_ORDER_DETAIL.ITEM_ID IS
'商品主键';

COMMENT ON COLUMN EB_ORDER_DETAIL.ITEM_NAME IS
'商品名称';

COMMENT ON COLUMN EB_ORDER_DETAIL.ITEM_NO IS
'商品编号:自动生成,不可重复,添加完成后不可修改。编号规则:一级目录数字“1”+7位数递增,裸机起始编号   10000001。7位数递增满时自动升为8位数。
编号根据EB_ITEM.CAT_TYPE获得,如实体商品为1(EB_ITEM.CAT_TYPE=1)


(删除
--实体起始编号:   10000001 虚拟起始编号:   20000001。
--注意:商品是否为手机或号卡,用其所属的类目来区分,CAT_ID为1的为手机,CAT_ID为2的为号卡。)
';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU_ID IS
'最小销售单元主键';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU IS
'货号';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU_IMG IS
'图片存储位置,1~5';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU_NAME IS
'SKU名称';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU_CAT_TYPE IS
'冗余EB_CAT里边的CAT_TYPE字段值,用以标示:0、不分类;1、实体;2、号卡;3、虚拟商品';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU_SPEC IS
'规格1:规格2:规格3。。。规格N,格式参见订单需求文档';

COMMENT ON COLUMN EB_ORDER_DETAIL.MARKET_PRICE IS
'(以分币为单位)市场价:所有价格相关的字段限定为9位有效数字以内(即1234567.89,相当于千万元以内),给前端用户显示时,小数永远保持2位,即整数价格后面显示为.00;若小数价格多于2位小数,则直接截掉2位小数右边的小数(不用四舍五入);若小数为1位,如1元9角,则显示1.90';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU_DISCOUNT IS
'优惠额';

COMMENT ON COLUMN EB_ORDER_DETAIL.SKU_PRICE IS
'sku销售价';

COMMENT ON COLUMN EB_ORDER_DETAIL.OFFER_GROUP_NAME IS
'活动名称';

COMMENT ON COLUMN EB_ORDER_DETAIL.OFFER_TYPE IS
'活动类型:1:购物送礼;2:优惠购机;3:购机返话费';

COMMENT ON COLUMN EB_ORDER_DETAIL.SHORT_NAME IS
'活动简称。用字母代表,如A1中的A';

COMMENT ON COLUMN EB_ORDER_DETAIL.OFFER_ID IS
'促销活动主键';

COMMENT ON COLUMN EB_ORDER_DETAIL.OFFER_NAME IS
'活动档次简介';

COMMENT ON COLUMN EB_ORDER_DETAIL.OFFER_NO IS
'活动档次编号:起始编号: 50000001';

COMMENT ON COLUMN EB_ORDER_DETAIL.SHORT_NAME2 IS
'活动档次数字编号,如A1中的1';

COMMENT ON COLUMN EB_ORDER_DETAIL.OFFER_TERM IS
'业务协议期:1:6个月;2:12个月;3:18个月;4:24个月';

COMMENT ON COLUMN EB_ORDER_DETAIL.COMMIT_MONTHLY IS
'(以分币为单位)月承诺消费金额。大于0小于10000的整数';

COMMENT ON COLUMN EB_ORDER_DETAIL.PREPAID IS
'(以分币为单位)预存话费金额。大于0小于10000的整数';

COMMENT ON COLUMN EB_ORDER_DETAIL.PERIOD IS
'返还期。1:立即到帐;2:6个月;3:12个月;4:18个月;5:24个月';

COMMENT ON COLUMN EB_ORDER_DETAIL.REFUND_MONTHLY IS
'(以分币为单位)月返还金额。大于0小于10000的整数';

COMMENT ON COLUMN EB_ORDER_DETAIL.REFUND_1ST_MONTH IS
'(以分币为单位)首月返还金额。大于0小于10000的整数';

COMMENT ON COLUMN EB_ORDER_DETAIL.REFUND_LAST_MONTH IS
'(以分币为单位)末月返还金额。大于0小于10000的整数';

COMMENT ON COLUMN EB_ORDER_DETAIL.ORDER_DETAIL_TYPE IS
'1、SKU;2、OFFER;3、营销案的SKU';

COMMENT ON COLUMN EB_ORDER_DETAIL.QUANTITY IS
'数量';

COMMENT ON COLUMN EB_ORDER_DETAIL.PRICE IS
'(以分币为单位)成交价格(即实际购买价格)。若是营销活动,则按公式sku_price+prepaid-sku_discount计算';

COMMENT ON COLUMN EB_ORDER_DETAIL.SERIESCODE IS
'串号,逗号分割';

COMMENT ON COLUMN EB_ORDER_DETAIL.OFFER_GROUP_NO IS
'活动编号,用来存储从crm过来的编号';

COMMENT ON COLUMN EB_ORDER_DETAIL.PROMO_TYPE IS
'活动类型,用来存储从crm返回的活动类型,在营销案开通接口中使用';

COMMENT ON COLUMN EB_ORDER_DETAIL.COND_ID IS
'活动档次编码,从crm传过来的';


复制代码

我们对这两张表逆向工程!

order表

插入mapper的SQL语句、主键需要返回、一些属性可默认插入


<insert id="insert" parameterType="com.rl.ecps.model.EbOrder">
    <selectKey keyProperty="orderId" order="BEFORE" resultType="long">
      select seqorderid.nextval from dual
    </selectKey>
    insert into EB_ORDER (ORDER_ID, PTL_USER_ID, USERNAME,
    ORDER_NUM, PAYMENT, PAY_PLATFORM,
    DELIVERY, IS_CONFIRM, ORDER_SUM,
    SHIP_FEE, IS_PAID, ORDER_STATE,
    PAYMENT_CASH, DISTRI_ID, DELIVERY_METHOD,
    PAYMENT_NO, ORDER_TIME, PAY_TIME,
    DEPOSIT_TIME, SUCCESS_TIME, UPDATE_TIME,
    SRV_TYPE, SELF_COLLECT_SITE, SELF_COLLECT_SITE_ID,
    IS_DELETED, IS_DISPLAY, NOTES,
    SHIP_NAME, PROVINCE, CITY,
    DISTRICT, ZIP_CODE, ADDR,
    PHONE, PAYABLE, COMPANY,
    CONTENTS, IS_CALL, DELIVERY_NO,
    AREA_CODE, AREA_NAME, IS_PRINT,
    CRM_CALLS_TIME, IS_OFFER_RELEASE, JOB_NUM,
    ORDER_TYPE, FIXED_PHONE, ATTACH_FILE,
    RETURN_TYPE, SECKILL_ID, ORDER_SOURCE,
    ORDER_EXT1, ORDER_EXT2, ORDER_EXT3,
    ORDER_EXT4, ORDER_EXT5)
    values (#{orderId,jdbcType=DECIMAL}, #{ptlUserId,jdbcType=DECIMAL}, #{username,jdbcType=VARCHAR},
    #{orderNum,jdbcType=VARCHAR}, #{payment,jdbcType=DECIMAL}, #{payPlatform,jdbcType=DECIMAL},
    #{delivery,jdbcType=DECIMAL}, #{isConfirm,jdbcType=DECIMAL}, #{orderSum,jdbcType=DECIMAL},
    #{shipFee,jdbcType=DECIMAL}, 0, #{orderState,jdbcType=DECIMAL},
    #{paymentCash,jdbcType=DECIMAL}, #{distriId,jdbcType=DECIMAL}, #{deliveryMethod,jdbcType=DECIMAL},
    #{paymentNo,jdbcType=VARCHAR}, sysdate, #{payTime,jdbcType=TIMESTAMP},
    #{depositTime,jdbcType=TIMESTAMP}, #{successTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP},
    #{srvType,jdbcType=DECIMAL}, #{selfCollectSite,jdbcType=VARCHAR}, #{selfCollectSiteId,jdbcType=DECIMAL},
    #{isDeleted,jdbcType=DECIMAL}, #{isDisplay,jdbcType=DECIMAL}, #{notes,jdbcType=VARCHAR},
    #{shipName,jdbcType=VARCHAR}, #{province,jdbcType=VARCHAR}, #{city,jdbcType=VARCHAR},
    #{district,jdbcType=VARCHAR}, #{zipCode,jdbcType=VARCHAR}, #{addr,jdbcType=VARCHAR},
    #{phone,jdbcType=VARCHAR}, #{payable,jdbcType=DECIMAL}, #{company,jdbcType=VARCHAR},
    #{contents,jdbcType=DECIMAL}, 0, #{deliveryNo,jdbcType=VARCHAR},
    #{areaCode,jdbcType=VARCHAR}, #{areaName,jdbcType=VARCHAR}, #{isPrint,jdbcType=DECIMAL},
    #{crmCallsTime,jdbcType=TIMESTAMP}, #{isOfferRelease,jdbcType=DECIMAL}, #{jobNum,jdbcType=VARCHAR},
    #{orderType,jdbcType=DECIMAL}, #{fixedPhone,jdbcType=VARCHAR}, #{attachFile,jdbcType=VARCHAR},
    #{returnType,jdbcType=DECIMAL}, #{seckillId,jdbcType=DECIMAL}, #{orderSource,jdbcType=DECIMAL},
    #{orderExt1,jdbcType=VARCHAR}, #{orderExt2,jdbcType=VARCHAR}, #{orderExt3,jdbcType=VARCHAR},
    #{orderExt4,jdbcType=VARCHAR}, #{orderExt5,jdbcType=VARCHAR})
  </insert>
复制代码

编写对应的Dao


/**
 * 继承SqlSessionDaoSupport能够得到sessionFactory的引用,非常方便!
        */
@Repository
public class EbOrderDaoImpl extends SqlSessionDaoSupport implements EbOrderDao {

    String nameSpace = "com.rl.ecps.sqlMap.EbOrderMapper.";

    public void saveOrder(EbOrder order) {
        this.getSqlSession().insert(nameSpace + "insert", order);
    }
}

复制代码

orderDetail

orderDetail的主键是序列自动生成的;


seqorderdetailid.nextval,
复制代码

编写Dao


public interface EbOrderDetailDao {

    /**
     * 这里保存的并不是List集合,因为考虑到了并发的问题,这里最好使用单个实体
     * 即时一个订单中有多个订单项,这里使用单个实体会方便一点!
     * 并且订单明细中还需要获取得出库存的数据、还要对库存进行操作。
     * @param orderDetail
     */
    void saveOrderDetail(EbOrderDetail orderDetail);



}

复制代码


/**
 * 继承SqlSessionDaoSupport能够得到sessionFactory的引用,非常方便
 */
@Repository
public class EbOrderDetailDaoImpl extends SqlSessionDaoSupport implements EbOrderDetailDao {
    String nameSpace = "com.rl.ecps.sqlMap.EbOrderDetailMapper.";
    public void saveOrderDetail(EbOrderDetail orderDetail) {
        this.getSqlSession().insert(nameSpace + "insert", orderDetail);
    }
}
复制代码

编写Service


public interface EbOrderService {

    /**
     * 因为在订单提交完毕后,我们是需要把购物车的数据清空的。
     * 将购物车的数据清空实际上就是清空cookie的数据!
     * 因此需要request和response对象!
     * @param ebOrder
     * @param details
     * @param request
     * @param response
     */
    void addOrder(EbOrder ebOrder, List<EbOrderDetail> details, HttpServletRequest request , HttpServletResponse response);

}

复制代码

接下来就是获取页面的参数、将数据保存到Order和OrderDetail中了

Controller



    /**
     * 获取页面的参数、保存订单!
     * @param session
     * @param model
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/SubmitOrder.do")
    public String SubmitOrder(HttpSession session, Model model, HttpServletRequest request,HttpServletResponse response,EbOrder order,String address) throws InvocationTargetException, IllegalAccessException {

        //设置订单的信息
        TsPtlUser user = (TsPtlUser) session.getAttribute("user");
        if(user != null){
            order.setPtlUserId(user.getPtlUserId());
            order.setUsername(user.getUsername());
        }
        order.setOrderNum(new SimpleDateFormat().format(new Date()));

        //收集地址分为两种:一种是新增,一种是使用原有的。
        //如果使用原有的,那么带过来的是id,我们可以直接获取对应的数据,封装到order对象中。
        if(!StringUtils.equals("add", address)){
            EbShipAddr addr = addrService.selectByPrimaryKey(new Long(address));
            BeanUtils.copyProperties(order, addr);
        }

        //订单明细和购物车清单的数据是一样的。
        List<EbOrderDetail> detailList = new ArrayList<EbOrderDetail>();

        List<EbCart> cartList = cartService.listCart(request, response);

        //遍历购物车的清单,将数据加入到订单明细中
        for(EbCart cart:cartList){
            EbOrderDetail detail = new EbOrderDetail();
            detail.setItemId(cart.getSku().getItem().getItemId());
            detail.setItemName(cart.getSku().getItem().getItemName());
            detail.setItemNo(cart.getSku().getItem().getItemNo());
            detail.setSkuId(cart.getSkuId());
            String specVal = "";
            List<EbSpecValue> specList = cart.getSku().getSpecList();
            for(EbSpecValue spec : specList){
                specVal = specVal + spec.getSpecValue()+",";
            }
            specVal = specVal.substring(0, specVal.length() - 1);
            detail.setSkuSpec(specVal);
            detail.setQuantity(cart.getQuantity());
            detail.setSkuPrice(cart.getSku().getSkuPrice());
            detail.setMarketPrice(cart.getSku().getMarketPrice());
            detailList.add(detail);
        }
        orderService.addOrder(order, detailList, request, response);
        model.addAttribute("order", order);

        return "shop/confirmProductCase2";
    }

复制代码

Service流程步骤

用户提交了订单的话,那么我们要做什么事呢???

  • 将库存的数量减少
  • 清空购物车数据

库存的数据减少这里涉及到了并发的问题:

  • 如果两个用户同时提交订单的话,当前的库存是1,一个提交了订单,另一个应该是没货的。
  • 但如果我们不做任何操作的话,那么库存会减成是0
  • 这样明显是不合理的

于是我们就需要对这个操作“上锁”

锁有两种:

  • 乐观锁
    • 在修改数据的时候把事务锁起来,通过version的方式来进行锁定
  • 悲观锁
    • 在查询完数据的时候就把事务锁起来,直到提交事务

悲观锁:

乐观锁:

但其实我们现在这个操作并不需要用到悲观锁和乐观锁。因为我们查询出来的数据不用做另一番操作

  • 我们写一条SQL语句就能够搞掂了

  <update id="updateStock" parameterType="map">
  	update eb_sku t  set t.stock_inventory = t.stock_inventory - #{quantity} where sku_id = #{skuId} 
  	and t.stock_inventory > =#{quantity}
  </update>


复制代码

service编写:

   public void addOrder(EbOrder ebOrder, List<EbOrderDetail> details, HttpServletRequest request, HttpServletResponse response) {

        orderDao.saveOrder(ebOrder);

        Map<String,Object> map = new HashMap<String,Object>();
        for(EbOrderDetail detail : details){
            detail.setOrderId(ebOrder.getOrderId());
            detailDao.saveOrderDetail(detail);

			/*EbSku sku = skuDao.getSkuById(detail.getSkuId());

			sku.setStockInventory(sku.getStockInventory() - detail.getQuantity());
			skuDao.update(sku);*/
            map.put("skuId", detail.getSkuId());
            map.put("quantity", detail.getQuantity());
            int flag = skuDao.updateStock(map);
            if(flag == 0){
                throw new EbStockException("库存不足");
            }

        }
        cartService.clearCar(request, response);
    }
复制代码

走一遍流程:

总结

  • 查询出订单表所需要的数据、在页面上展示出来
  • OrderDetail在Dao保存的时候不再使用List来作为参数,而是直接使用OrderDetail实体来作为参数。因为考虑到了并发的问题,还需要OrderDetail的数据去操作库存。因此直接使用实体作为参数。
  • 在确认订单需要确认库存是否充足,在完成订单之后需要把购物车清空!
  • 悲观锁:在查询出数据之后就把事务锁起来
  • 客观锁:在修改数据的时候通过version将事务锁起来
  • 如果查询出来的数据没有被多次操作的话,那我们可以考虑是不是可以使用一条SQL语句就能够完成我们的任务了。

如果您觉得这篇文章帮助到了您,可以给作者一点鼓励

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值