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语句就能够完成我们的任务了。
如果您觉得这篇文章帮助到了您,可以给作者一点鼓励