在介紹這篇文章之前我們先了解一下
Q1.什么是統(tǒng)一下單
大家如果做過微信狠半、支付寶支付的話设塔,那一定用過統(tǒng)一下單這個(gè)接口愉粤。
這里我們以微信支付為例
微信支付文檔:https://pay.weixin.qq.com/wiki/doc/api/index.html
在
trade_type參數(shù)中我們有很多中選擇断楷,不同的參數(shù)代表我們不同的場景响委,不同的場景校驗(yàn)的參數(shù)以及鏈路是不同的铃辖,比如在小程序剩愧、微信內(nèi)置支付需要傳遞OpenId
Q2.統(tǒng)一下單解決了什么
提供了一個(gè)清晰對(duì)外的接口,根據(jù)傳入不同的參數(shù)來決定不同的鏈路方向以及返回不同的結(jié)果
電商應(yīng)用場景
在電商項(xiàng)目中,我們也會(huì)有統(tǒng)一下單的場景娇斩,比如我們有普通商品仁卷、新用戶專享活動(dòng)商品穴翩、會(huì)員用戶專享活動(dòng)商品、而活動(dòng)商品是基于普通商品轉(zhuǎn)換過來的(可能這里說的比較抽象锦积,給大家上一幅簡易的圖來解釋)
t_spu芒帕、t_sku表是所有商品的基礎(chǔ)信息以及價(jià)格(簡稱為普通商品)
t_activity_prod表是活動(dòng)商品信息,引入基礎(chǔ)表的spu_id丰介、sku_id
背蟆。但活動(dòng)商品的價(jià)格(price)、庫存(stock)則需要獨(dú)立添加哮幢,因?yàn)樵陔娚添?xiàng)目中带膀,活動(dòng)商品的價(jià)格比普通商品更低,并且?guī)齑孢€有限制
不同訂單不同走向
普通商品和活動(dòng)商品訂單流程也是不同的橙垢,這里以支付回調(diào)后的清算為例子(參考下圖)
普通商品清算后需要核銷使用的優(yōu)惠券和積分
活動(dòng)商品清算則需要核銷新人或新會(huì)員的專享機(jī)會(huì)(假設(shè)只能購買一次)
代碼中如何實(shí)現(xiàn)
在電商項(xiàng)目中一個(gè)支付成功訂單的生成分為三步
【確認(rèn)訂單】垛叨、【提交訂單并支付】、【訂單支付回調(diào)】
廢話不多說钢悲,我們直接開搞点额!前方高能!]毫铡;估狻!惭等!前方高能U涫帧!4亲觥A找!前方高能3用V刹埂!?蛟课幕!
/**
* 統(tǒng)一訂單支付服務(wù) 2020年12月30日 13點(diǎn)49分
*
* @author bandari
*/
public interface OrderServiceFactory {
/**
* 統(tǒng)一確認(rèn)訂單
*
* @param configOrderBo 統(tǒng)一確認(rèn)訂單入?yún)? * @return 統(tǒng)一確認(rèn)訂單出參
*/
UnifiedConfigOrderVo unifiedConfigOrder(UnifiedConfigOrderBo configOrderBo);
/**
* 統(tǒng)一提交訂單
*
* @param submitOrderBo 統(tǒng)一提交訂單入?yún)? * @return 統(tǒng)一提交訂單出參
*/
UnifiedSubmitOrderVo unifiedSubmitOrder(ConfigOrderDTO configOrderDTO);
/**
* 統(tǒng)一訂單支付成功后的事件處理
*
* @param paySuccessOrderBo 支付成功訂單入?yún)? * @return 支付成功訂單出參
*/
UnifiedPaySuccessOrderVo unifiedPaySuccessOrder(UnifiedPaySuccessOrderBo paySuccessOrderBo);
/**
* 統(tǒng)一訂單退款成功后的事件處理
*
* @param refundSuccessOrderBo 退款成功訂單入?yún)? * @return 退款成功訂單出參
*/
UnifiedRefundSuccessOrderVo unifiedRefundSuccessOrder(
UnifiedRefundSuccessOrderBo refundSuccessOrderBo);
普通訂單、新人專享訂單五垮、新會(huì)員訂單重寫這個(gè)接口
/**
* 普通訂單服務(wù)
* 注意這里的orderServiceFactory1
* @author bandari
*/
@Slf4j
@Service("orderServiceFactory1")
public class OrdinaryOrderServiceFactoryImpl implements OrderServiceFactory {
@Override
public UnifiedConfigOrderVo unifiedConfigOrder(UnifiedConfigOrderBo configOrderBo) {
log.info("");
log.info("普通商品進(jìn)行確認(rèn)訂單操作:{}", JSONUtil.toJsonStr(configOrderBo));
log.info("校驗(yàn)普通商品是否存在乍惊、庫存是否充足等");
//這里用ThreadLocal 代替Redis
ConfigOrderDTO dto = new ConfigOrderDTO();
BeanUtils.copyProperties(configOrderBo, dto);
Map<String, ConfigOrderDTO> configOrderDTOMap = new HashMap<>();
configOrderDTOMap.put(Constant.CONFIG_ORDER_KEY, dto);
ThreadLocalCache.set(configOrderDTOMap);
log.info("====================普通商品確認(rèn)訂單操作完成===============");
return new UnifiedConfigOrderVo();
}
@Override
public UnifiedSubmitOrderVo unifiedSubmitOrder(ConfigOrderDTO configOrderDTO) {
log.info("");
log.info("普通商品提交訂單操作:{}", JSONUtil.toJsonStr(configOrderDTO));
log.info("生成訂單及清算信息");
log.info("====================普通商品提交訂單操作完成===============");
return new UnifiedSubmitOrderVo();
}
@Override
public UnifiedPaySuccessOrderVo unifiedPaySuccessOrder(
UnifiedPaySuccessOrderBo paySuccessOrderBo) {
log.info("");
log.info("普通商品支付成功后的操作:{}", JSONUtil.toJsonStr(paySuccessOrderBo));
log.info("核銷優(yōu)惠券、積分放仗、");
log.info("====================普通商品支付成功后的操作完成===============");
return new UnifiedPaySuccessOrderVo();
}
@Override
public UnifiedRefundSuccessOrderVo unifiedRefundSuccessOrder(
UnifiedRefundSuccessOrderBo refundSuccessOrderBo) {
log.info("普通商品退款成功后的操作:{}", JSONUtil.toJsonStr(refundSuccessOrderBo));
return new UnifiedRefundSuccessOrderVo();
}
/**
* 新人專享訂單服務(wù)
* 注意這里的orderServiceFactory2
* @author bandari
*/
@Slf4j
@Service("orderServiceFactory2")
public class NewPeopleOrderServiceFactoryImpl implements OrderServiceFactory {
@Override
public UnifiedConfigOrderVo unifiedConfigOrder(UnifiedConfigOrderBo configOrderBo) {
log.info("");
log.info("新人專享商品進(jìn)行確認(rèn)訂單操作:{}", JSONUtil.toJsonStr(configOrderBo));
log.info("校驗(yàn)新人專享商品是否存在润绎、庫存、新人專享機(jī)會(huì)等條件是否充足等");
//這里用ThreadLocal 代替Redis
ConfigOrderDTO dto = new ConfigOrderDTO();
BeanUtils.copyProperties(configOrderBo, dto);
Map<String, ConfigOrderDTO> configOrderDTOMap = new HashMap<>();
configOrderDTOMap.put(Constant.CONFIG_ORDER_KEY, dto);
ThreadLocalCache.set(configOrderDTOMap);
log.info("====================新人專享商品確認(rèn)訂單操作完成===============");
return new UnifiedConfigOrderVo();
}
@Override
public UnifiedSubmitOrderVo unifiedSubmitOrder(ConfigOrderDTO configOrderDTO) {
log.info("");
log.info("新人專享商品提交訂單操作:{}", JSONUtil.toJsonStr(configOrderDTO));
log.info("生成訂單及清算信息");
log.info("====================新人專享商品提交訂單操作完成===============");
return new UnifiedSubmitOrderVo();
}
@Override
public UnifiedPaySuccessOrderVo unifiedPaySuccessOrder(
UnifiedPaySuccessOrderBo paySuccessOrderBo) {
log.info("");
log.info("新人專享商品訂單支付成功后的操作");
log.info("核銷優(yōu)惠券、積分莉撇、");
log.info("核銷新人專享機(jī)會(huì)");
log.info("====================新人專享商品支付成功操作完成===============");
return new UnifiedPaySuccessOrderVo();
}
@Override
public UnifiedRefundSuccessOrderVo unifiedRefundSuccessOrder(
UnifiedRefundSuccessOrderBo refundSuccessOrderBo) {
log.info("新人專享商品退款成功后的操作:{}", JSONUtil.toJsonStr(refundSuccessOrderBo));
return new UnifiedRefundSuccessOrderVo();
}
}
/**
* 新會(huì)員專享訂單服務(wù)
* 注意這里的orderServiceFactory3
* @author bandari
*/
@Slf4j
@Service("orderServiceFactory3")
public class NewMemberOrderServiceFactoryImpl implements OrderServiceFactory {
@Override
public UnifiedConfigOrderVo unifiedConfigOrder(UnifiedConfigOrderBo configOrderBo) {
log.info("");
log.info("新會(huì)員專享商品進(jìn)行確認(rèn)訂單操作:{}", JSONUtil.toJsonStr(configOrderBo));
log.info("校驗(yàn)新會(huì)員專享商品是否存在呢蛤、庫存、新會(huì)員專享機(jī)會(huì)稼钩、是否為會(huì)員等條件是否充足等");
//這里用ThreadLocal 代替Redis
ConfigOrderDTO dto = new ConfigOrderDTO();
BeanUtils.copyProperties(configOrderBo, dto);
Map<String, ConfigOrderDTO> configOrderDTOMap = new HashMap<>();
configOrderDTOMap.put(Constant.CONFIG_ORDER_KEY, dto);
ThreadLocalCache.set(configOrderDTOMap);
log.info("====================新會(huì)員專享商品確認(rèn)訂單操作完成===============");
return new UnifiedConfigOrderVo();
}
@Override
public UnifiedSubmitOrderVo unifiedSubmitOrder(ConfigOrderDTO configOrderDTO) {
log.info("");
log.info("新會(huì)員專享商品提交訂單操作:{}", JSONUtil.toJsonStr(configOrderDTO));
log.info("生成訂單及清算信息");
log.info("====================新會(huì)員專享商品提交訂單操作完成===============");
return new UnifiedSubmitOrderVo();
}
@Override
public UnifiedPaySuccessOrderVo unifiedPaySuccessOrder(
UnifiedPaySuccessOrderBo paySuccessOrderBo) {
log.info("");
log.info("新會(huì)員專享商品訂單支付成功后的操作");
log.info("核銷優(yōu)惠券顾稀、積分、");
log.info("核銷新會(huì)員專享機(jī)會(huì)");
log.info("新增會(huì)員成長值");
log.info("====================新會(huì)員專享商品支付成功操作完成===============");
return new UnifiedPaySuccessOrderVo();
}
@Override
public UnifiedRefundSuccessOrderVo unifiedRefundSuccessOrder(
UnifiedRefundSuccessOrderBo refundSuccessOrderBo) {
log.info("新會(huì)員專享商品退款成功后的操作:{}", JSONUtil.toJsonStr(refundSuccessOrderBo));
return new UnifiedRefundSuccessOrderVo();
}
}
不同訂單不同走向坝撑,所以我們需要一個(gè)ProdType參數(shù)來控制方向
/**
* 工廠服務(wù),可抽離出一個(gè)接口(此處省略)
*/
@Component
public class MasterFactory implements Serializable {
@Autowired
private Map<String, OrderServiceFactory> orderServiceMap;
/**
* 獲取商品對(duì)應(yīng)的訂單服務(wù)
*
* @param prodType 商品類型
* @return 返回對(duì)應(yīng)的訂單服務(wù)
*/
@SneakyThrows
public OrderServiceFactory getOrderService(Integer prodType) {
OrderServiceFactory orderServiceFactory = orderServiceMap.get("orderServiceFactory" + prodType);
if (ObjectUtil.isNull(orderServiceFactory)) {
throw new Exception("訂單服務(wù)不存在");
}
return orderServiceFactory;
}
}
項(xiàng)目測試案例
@SpringBootTest
@Slf4j
@WebAppConfiguration
class OrderTest {
@Autowired
private OrderController orderController;
@BeforeEach
public void configOrder() {
//模擬確認(rèn)訂單
UnifiedConfigOrderBo configOrderBo = new UnifiedConfigOrderBo();
configOrderBo.setNum(1);
configOrderBo.setSpuId(1L);
configOrderBo.setSkuId(2L);
//NEW_MEMBER:新會(huì)員專享商品 NEW_PEOPLE:新人專享商品 ORDINARY:普通商品
configOrderBo.setProdType(ProdTypeEnum.NEW_MEMBER.getCode());
orderController.unifiedConfigOrder(configOrderBo);
}
@Test
public void submitOrder() {
//模擬提交訂單
orderController.unifiedSubmitOrder();
}
@AfterEach
public void paySuccessOrder() {
//模擬訂單支付成功
orderController
.unifiedPaySuccessOrder(new UnifiedPaySuccessOrderBo());
}
}
當(dāng)ProdType為NEW_MEMBER(新會(huì)員專享)静秆,訂單日志流程如下
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl :
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : 新會(huì)員專享商品進(jìn)行確認(rèn)訂單操作:{"num":1,"prodType":3,"spuId":1,"skuId":2}
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : 校驗(yàn)新會(huì)員專享商品是否存在、庫存巡李、新會(huì)員專享機(jī)會(huì)抚笔、是否為會(huì)員等條件是否充足等
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : ====================新會(huì)員專享商品確認(rèn)訂單操作完成===============
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl :
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : 新會(huì)員專享商品提交訂單操作:{"num":1,"prodType":3,"spuId":1,"skuId":2}
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : 生成訂單及清算信息
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : ====================新會(huì)員專享商品提交訂單操作完成===============
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl :
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : 新會(huì)員專享商品訂單支付成功后的操作
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : 核銷新會(huì)員專享機(jī)會(huì)
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : 新增會(huì)員成長值
[ main] b.f.s.i.NewMemberOrderServiceFactoryImpl : ====================新會(huì)員專享商品支付成功操作完成===============
當(dāng)ProdType為NEW_PEOPLE(新人專享),訂單日志流程如下
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl :
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : 新人專享商品進(jìn)行確認(rèn)訂單操作:{"num":1,"prodType":2,"spuId":1,"skuId":2}
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : 校驗(yàn)新人專享商品是否存在侨拦、庫存殊橙、新人專享機(jī)會(huì)等條件是否充足等
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : ====================新人專享商品確認(rèn)訂單操作完成===============
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl :
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : 新人專享商品提交訂單操作:{"num":1,"prodType":2,"spuId":1,"skuId":2}
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : 生成訂單及清算信息
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : ====================新人專享商品提交訂單操作完成===============
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl :
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : 新人專享商品訂單支付成功后的操作
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : 核銷新人專享機(jī)會(huì)
[ main] b.f.s.i.NewPeopleOrderServiceFactoryImpl : ====================新人專享商品支付成功操作完成===============
當(dāng)ProdType為ORDINARY(普通商品),訂單日志流程如下
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl :
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : 普通商品進(jìn)行確認(rèn)訂單操作:{"num":1,"prodType":1,"spuId":1,"skuId":2}
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : 校驗(yàn)普通商品是否存在狱从、庫存是否充足等
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : ====================普通商品確認(rèn)訂單操作完成===============
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl :
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : 普通商品提交訂單操作:{"num":1,"prodType":1,"spuId":1,"skuId":2}
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : 生成訂單及清算信息
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : ====================普通商品提交訂單操作完成===============
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl :
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : 普通商品支付成功后的操作:{}
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : 核銷優(yōu)惠券膨蛮、積分、
[ main] .b.f.s.i.OrdinaryOrderServiceFactoryImpl : ====================普通商品支付成功后的操作完成===============
好了季研,上述就是作者在電商項(xiàng)目中寫的【統(tǒng)一下單】流程敞葛,并已滿足現(xiàn)存業(yè)務(wù)場景;關(guān)于這個(gè)流程實(shí)現(xiàn)的方法有很多与涡。每個(gè)人都有不同的想法和見解惹谐。希望這篇文章能給你一些新的啟發(fā)。
最后
上述代碼已經(jīng)上傳至GitHub驼卖。有需要的同學(xué)去上面看看吧氨肌。
項(xiàng)目案例地址:https://github.com/gitbandari/example-unifiedorder
后續(xù)作者將會(huì)更新一期電商優(yōu)惠券的設(shè)計(jì),敬請(qǐng)期待酌畜。
歡迎各位同學(xué)的點(diǎn)贊怎囚、收藏、評(píng)論