1、PC端
第一步
调用下单接口去后台下单
/pc/course/tryToSignUpCourse.do
第二步
拿到后台传过来的订单号之后判断订单的状态
订单状态分为
1、已经支付成功 success 1
2、支付中paying 2
如果订单状态是支付中
拿着orderId ,courseId跳转到支付页面
3、到达支付页面之后
第一步后去调用/pc/memberAccount/getMemberAccount.do获取账户余额
第二步调用
pc/order/getByOrderNO.do 根据订单号获取订单信息
第三步 选择微信或者支付宝,点击立即支付
调用 /pay/alipayDeposit.do进行支付,并且加入支付类型参数,是微信,或者支付宝,或者余额
后台会做相应判断
如果是余额支付:支付成功倒计时三秒立即跳回上一页
如果是微信支付:拿到后台的支付聘证数据(微信返回的),生成二位码
并且同时开启轮询查询支付成功后查询订单支付结果,如果状态变为成功,则跳回上一页
// 微信支付返回结果
weChatPayResult () {
this.timer = setInterval(() => {
const params = {
orderNO: this.$route.query.orderNO
}
this.$post('/pc/order/getByOrderNO.do', params).then((res) => {
if (res && res.status === 'PAYMENTSUCCESSED') {
clearInterval(this.timer)
this.paySuccessType()
}
})
}, 5000)
},
如果是支付宝
拿到后台发布会的订单号跳转到指定的二位码页面
并且同时开启轮询查询支付成功后查询订单支付结果,如果状态变为成功,则跳回上一页
this.$post('/pay/alipayDeposit.do', {}, data).then((res) => {
if (res) {
let routerData = this.$router.resolve({ path: '/Alipay', query: { htmlData: res } })
console.log(routerData)
// 打开新页面
window.open(routerData.href, '_ blank')
}
})
2、wap端
第一步
去后台下单
this.$post('/wap/course/tryToSignUpCourse.do?t=' + new Date().getTime() + '&mm=' + res.id, data, {}).then((response) => {
if (!response.errorCode) {
if (response.status == 'SUCCESS') {
window.location.reload()
} else if (response.status == 'PAYING') {
if (!this.isLogin) {
this.$router.togo({path: '/login', query: {lastUrl: this.$route.fullPath}})
} else {
this.$router.togo({
path: '/selectPayModel',
query: {navType: 'Curriculum', orderNO: response.order.orderNO}
})
}
}
}
})
}
第二步
拿到订单号后之后跳转到支付页面,支付页面有选择支付宝或者余额支付,选择后点击立即支付按钮
第三步
点击立即用微信支付之后,调用接口获取订单信息
// 获取订单信息
getorderNOInfo() {
const params = {
orderNO: this.$route.query.orderNO,
t: new Date().getTime()
}
this.$post("/wap/order/getByOrderNO.do", params).then((res) => {
if (res.id) {
this.goodsType = res.goodsType
if (res.goodsType === 'COURSE_GROUP_BUY') {
this.totalFee = res.groupTotalFee
this.goodsName = res.goodsName
this.goodsId = res.goodsId
} else {
this.totalFee = res.totalFee
this.goodsName = res.goodsName
this.goodsId = res.goodsId
}
this.weChatPaySuccess(this.$common.getAllUrlParams().code,this.$common.getAllUrlParams().state)
}
})
},
关键的一步
订单拿到成功之后微信会给予一个code 和state
this.weChatPaySuccess(this.$common.getAllUrlParams().code,this.$common.getAllUrlParams().state)
拿到code,state之后调用后台的/pay/alipayDeposit.do接口进行发起支付
weChatPaySuccess(code,state) {
if (!code||!state) {//为空表示没收到回调
return;
}
const mystate = this.calcuMD5('wx_pay_XXX')//MD5加密
if (mystate !== state) {
return;
}
this.payTpye = 'weixin'
let data = {
payMode: 'WEIXIN',
payType: 'ORDER',
code:code,
tradeType: 'JSAPI',
order: {
payFee: this.totalFee,
orderNO: this.$route.query.orderNO,
tradeType: 'JSAPI'
}
}
this.$post('/pay/alipayDeposit.do', {}, data).then((res) => {
if (!res.errorCode) {
if(typeof WeixinJSBridge === "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
this.onBridgeReady(res);
}
}
})
},
//这段代码是微信支付文档里抄过来的,用来弹出支付弹框
onBridgeReady(params) {
var that = this
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":'wxefdc984d5aebe82f',
"timeStamp":params.timestamp+'',
"nonceStr":params.noncestr+'',
"package": 'prepay_id=' + params.prepayId+'',
"signType":'MD5',
"paySign": params.sign+''
},
function (res) {
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
if (res.err_msg == "get_brand_wcpay_request:ok") {
//到这里表示支付成功,处理支付成功的后续逻辑即可
that.weChatPayResult();
} else {
这里表示支付失败,重新刷新页面
window.location.href = that.$qr + 'wap3/#/selectPayModel?orderNO=' + that.$route.query.orderNO
}
}
)
},
返回成功之后再次查询订单状态
// 微信支付返回结果
weChatPayResult () {
const params = {
orderNO: this.$route.query.orderNO
}
this.$post("/wap/order/getByOrderNO.do?t="+new Date().getTime(), params).then((res) => {
if (res && res.status === 'PAYMENTSUCCESSED') {
this.paySuccessType()
}
})
},
弹出支付成功,跳出回上级页面
paySuccessType() {
if (this.payTpye === 'weixin') {
Toast('微信支付成功')
this.$router.push({path: '/courseDetail', query: {courseId: this.goodsId}})
} else if (this.payTpye === 'account') {
Toast('余额支付成功')
this.$router.goBack()
}
}
3、app端
第一步
调用 app/course/tryToSignUpCourse.do接口下单
//调用下单接口获取订单号
[self.viewModel signUpCourseId:self.ID success:^(NSString *orderNO) {
[HQWebViewLoading removeFromSuperView:weakSelf.view];
if (STRING_ISNIL(orderNO)) {
NSString *my_key= [NSString stringWithFormat:@"%@%ld",[self.ID stringValue],(long)[UserManager shareInstance].memberBasicVO.ID];
[UserDefaults setInteger:0 forKey:my_key];
//重新请求视频播放路径
[weakSelf queryCourseDetailInfoWithIndicator:NO isRefreshPlayer:YES];
[SKStoreReviewController requestReview];
}else {
//拿到订单号弹出支付页面
[weakSelf jumpToPay:orderNO];
}
} Failure:^(NSError *error) {
[HQWebViewLoading removeFromSuperView:weakSelf.view];
}];
拿到订单号弹出支付页面
选择微信支付,支付宝支付,余额支付
调用app/pay/appDeposit.do 去微信支付宝后台获取订单号
拿到微信支付宝的订单号之后,拉起微信,支付宝 APP进行支付操作
总结所有的支付都只用到了后台的两个接口
1、app/course/tryToSignUpCourse.do 去后台下单
2、app/pay/appDeposit.do,去后台获取发起支付所需要的参数
4、后端实现
1)tryToSignUpCourse.do
@Override
public TryToSignUpVO tryToSignUpCourseForPaid(int memberId, int courseId) throws CcpException {
TryToSignUpVO sign = new TryToSignUpVO();
CourseEntity course = courseDAO.getDetailById(courseId, memberId);
//不能报名自己的课程
if (course.getCourse().getMemberId().equals(memberId)) {
throw new CcpException(CcpErrorCode.ERROR_COURSE_SHOULD_NOE_SIGNUP_SELF_ERROR);
}
CourseVO courseVO = convertToCourseVO(course, false);
//判断是否已经报名
if (courseVO.getIsSignedUp() == CcpBooleanEnum.TRUE) {
sign.setStatus(SignUpStatuEnum.SUCCESS);
return sign;
}
//判断是否免费
FeeTypeEnum feeType = courseVO.getBasicVO().getFeeType();
//免费
if (feeType == FeeTypeEnum.FREE) {
signUpCourse(memberId, courseId);
sign.setStatus(SignUpStatuEnum.SUCCESS);
//免费课报名,给课程作者发系统消息 TODO 免费课不发送
//systemMessageToCourseOwner(courseVO);
}
//收费
else {
//已经创建过订单:未支付,支付中
OrderVO oldOrder = orderService.getByMemberAndGoods(memberId, CcpModuleEnum.COURSE, courseId);
if (null != oldOrder && oldOrder.getId() != null) {
sign.setStatus(SignUpStatuEnum.PAYING);
sign.setOrder(oldOrder);
}
//需要创建新订单
else {
OrderVO order = createOrderVO(courseVO, memberId);
orderService.add(order);
sign.setStatus(SignUpStatuEnum.PAYING);
sign.setOrder(order);
}
}
return sign;
}
往订单表里面插入一条数据
@Override
public OrderVO add(OrderVO vo) throws CcpException
{
vo.setOrderNO(UUID.randomUUID().toString().replace("-", ""));
vo.setCreateTime(CcpDateUO.getInstance().getCurrentTimestamp());
TOrder tOrder = convertToEntity(vo);
dao.insert(tOrder);
vo.setId(tOrder.getId());
// 插入一条订单信息到表里,订单状态为支付中 paying。。。
processDao.insert(createOrderProcess(vo.getOrderNO(), vo.getStatus()));
return vo;
}
2)appDeposit.do
/**
* 订单付款时调用的接口
* 1.选择了支付宝支付,调用后返回支付宝的html,使用后会自动跳转到支付宝交易页面
* 2.选择了微信支付,调用后返回微信支付的二维码url
* 3.仅使用内部账户额度支付,此接口直接完成支付,页面刷新
* @param vo
*/
@RequestMapping(value = "alipayDeposit.do", method = RequestMethod.POST)
public void alipayDeposit(@RequestBody PayRequestVO requestVO, @PathParam("t") Long t)
{
try
{
Integer memberId = getCurrentMemberId();
if(requestVO.getTradeType() == null){
requestVO.setTradeType(WeixinPayTradeTypeEnum.NATIVE);
}
logger.debug("alipayDeposit : "+ requestVO);
orderCheck(requestVO, t, memberId);
if (requestVO.getPayMode() == PayModeEnum.ZHIFUBAO)
{
AliPayRequestVO alipayRequestVO = new AliPayRequestVO();
alipayRequestVO.setCreateIp(requestVO.getCreateIp());
alipayRequestVO.setOrder(requestVO.getOrder());
alipayRequestVO.setPayMode(requestVO.getPayMode());
alipayRequestVO.setPayType(requestVO.getPayType());
alipayRequestVO.setSerialNumber(requestVO.getSerialNumber());
AliPayResponseVO responseVO = (AliPayResponseVO) payServicePolicyBO.preparePay(alipayRequestVO);
returnString(responseVO.getsHtmlText());
}
else if (requestVO.getPayMode() == PayModeEnum.WEIXIN)
{
WeixinPayResponseVO responseVO = (WeixinPayResponseVO) payServicePolicyBO.preparePay(requestVO);
if(WeixinPayTradeTypeEnum.JSAPI == requestVO.getTradeType()){
logger.debug("alipayDeposit getPrepareResp:"+responseVO.getPrepareResp());
returnJSON(responseVO.getPrepareResp());
}else{
logger.debug("alipayDeposit getCodeUrl:"+responseVO.getPrepareResp().getCodeUrl());
returnObject(responseVO.getPrepareResp().getCodeUrl());
}
return;
}
else if (requestVO.getPayMode() == PayModeEnum.ACCOUNT)
{
//报名成功则设置订单支付成功,内部会调用公共的updateStatus,并在完成支付后执行各自业务
orderBO.setOrderSuccessForAccountPay(memberId, requestVO.getOrder(), requestVO.getOrder().getBusinessType());
//订单已经完成
returnSuccess();
}
else
{
returnFail();
return;
}
}
catch (Exception e)
{
returnError(CcpModuleEnum.MEMBER_ACCOUNT, e);
}
}