1. 发起支付
关键类:net.mingsoft.pay.action.web.PayAction.java 关键方法:geteway(....)
1.1. HTTP发送接口
HTTP方法:POST
请求URL:/mpay/pay/gateway.do
请求参数:
参数 | 是否必选 | 类型 | 可选值范围 | 默认值 | 说明 |
---|---|---|---|---|---|
type | 是 | String | weixin、alipay | 支付类型 | |
orderPrice | 是 | 价格 | |||
orderNo | 是 | String | 订单号 | ||
orderName | 是 | String | 订单名称 | ||
orderDesc | 是 | 商品描述 | |||
notifyUrl | 可选 | String | /mpay/alipay/notify.do /mpay/weixin/notify.do |
会根据 type 的值, 自动调用对应类型 |
|
attach | 是 | JSON | 扩展回调{'notifyBeanName':'回调方法','userId':'用户ID'} | ||
returnUrl | 是 | String | 只支持支付宝,支付成功结果页面,必须是http绝对路径 |
1.2. 支付回调
1.2.1. 默认回调地址
默认回调会可以完整基础订单支付
支付宝回调
/mpay/alipay/notify.do
微信回调
/mpay/weixin/notify.do
1.2.2. 扩展回调
大多数时候需要根据回调状态更新业务数据,通过 attach
参数中的 notifyBeanName
设置对应 spring
的 bean
名称实现
定义 class
实现 IPayNotify
接口
/**
* 支付时候,定义的attach的参数值
* @param payLogEntity 支付的日志信息
* @param attach {notifyBeanName:'业务扩展的bean,经过spring管理',自定义参数:值}
* @return
*/
@Service("diyPayNotify")
public class PayNotify implements IPayNotify {
@Override
public boolean notify(PayLogEntity payLog, HashMap attach) {
//订单号
//payLog.getOrderNo();
}
}
[!tip]
attach
定义格式{'notifyBeanName':'diyPayNotify'}
,也可以自定义参数,第三方支付平台
2. 范例
必须确保已经配置好了支付宝或者微信的相关配置
2.1. 支付宝支付
首先编写一个简单表单页面 "alipay.html"
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
...
<form>
<input type="text" name="returnUrl" value="http://localhost:8080"/><!--支付成功返回地址-->
<input type="text" name="orderNo" value="88888888"/><!--订单号-->
<input type="text" name="orderName" value="铭飞开源赞助"/><!--订单名称-->
<!--<input type="text" name="notifyUrl" value="自定义回调地址"/><!--回调地址,如果不填写默认为当前系统-->
<input type="text" name="type" value="alipay"/><!--支付类型-->
<input type="text" name="orderPrice" value="0.01"/><!--价格-->
<input type="text" name="orderDesc" value="价值源自分享"/><!--商品描述-->
<input type="text" name="showUrl" value="http://www.mingsoft.net"/><!--商品展示网址-->
</form>
...
<script>
$.ajax({
type: "POST",
dataType:"json",
url: "http://localhost:8080/mpay/pay/gateway.do",
data: $("form").serialize(),
success: function(res){
if(res.result) {
document.write(res.data);
}
}
});
</script>
2.2. 微信扫码支付
编写一个简单的表单页,根据表单提交的结果显示二维码图片,通常结合ajax来实现
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
...
<form>
<input type="hidden" name="orderNo" value="8"/><!--订单号-->
<input type="hidden" name="type" value="weixin"/><!--支付类型-->
<input type="hidden" name="orderPrice" value="0.01"/><!--价格-->
<input type="hidden" name="orderDesc" value="价值源自分享"/><!--商品描述-->
<!--<input type="text" name="notifyUrl" value="自定义回调地址"/><!--回调地址,如果不填写默认为当前系统-->
</form>
<!--显示二维码-->
<div id="qrcode"></div>
...
<script>
$.ajax({
type: "POST",
dataType:"json",
url: "http://localhost:8080/mpay/pay/gateway.do",
data: $("form").serialize(),
success: function(res){
if(res.result) {
$("#qrcode").qrcode(res.data);
} else {
alert('重新修改支付参数');
}
}
});
</script>
2.3. 微信公众号支付
微信公众号支付需要在公众号内部完成,同时用户需要进行授权登录,注意在前往授权登录的js中,请使用示例中 location.href 赋值的方式,使用window.open()的方式会遇到被拦截的情况
参考微信官方文档
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<!--创建支付表单页面-->
<form id="weixin" name="weixin" >
<input type="hidden" name="orderNo" value="888888888"/><!--订单编号-->
<input type="hidden" name="type" value="weixin"/><!--支付类型-->
<input type="hidden" name="orderPrice" value="0.01"/><!--价格-->
<input type="hidden" name="orderDesc" value="测试公众号支付"/><!--描述-->
<input type="hidden" name="page" value="http://项目地址/wx-mp-pay.jsp"/><!--接收微信支付授权信息的页面-->
<!--多个公众号支付必传-->
<input type="hidden" name="appId" value="xxxxxxxx"/><!--微信appId-->
<input type="hidden" name="mchId" value="1234567890"/><!--微信支付商户号-->
<input type="hidden" name="key" value="xxxxxxxx"/><!--微信支付API密钥-->
<input type="hidden" name="secret" value="xxxxxxxx"/><!--Appsecret-->
<input type="submit" value="确认">
</form>
...
<script>
//授权登录,需要用户配置微信appid和项目请求支付地址
function weixinPay(){
location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=微信appid&redirect_uri=" + encodeURIComponent("http://项目地址/mpay/pay/gateway.do?" + $("#weixin").serialize()) + "&response_type=code&scope=snsapi_userinfo#wechat_redirect";
}
</script>
确认支付
<!--确认支付页面-->
<script>
function pay() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":<%=request.getParameter("wxAppId")%>, //公众号名称,由商户传入
"timeStamp":"<%=request.getParameter("timeStamp")%>", //时间戳,自1970年以来的秒数
"nonceStr":"<%=request.getParameter("nonceStr")%>", //随机串
"package":"<%=request.getParameter("package")%>",
"signType":"MD5", //微信签名方式:
"paySign":"<%=request.getParameter("sign")%>" //微信签名
},
function(res){
if (res.err_msg == "get_brand_wcpay_request:ok") {
alert("微信支付成功!");
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
alert("用户取消支付!");
} else {
alert(JSON.stringify(res));
}
}
);
}
</script>
2.4. 微信刷卡支付
刷卡支付场景描述:用户出示微信付款二维码 、 商户使用扫码枪扫码,用户输入支付密码(小额免密),商务系统提示支付成功。
开发者需要制作一张支付表单页面,提交后直接返回支付结果
<!-- 微信刷卡支付,刷卡成功后会直接扣款,金额过大或其他原因会需要支付密码 -->
<!-- 具体参考微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_1 -->
<form id="submit" name="weixin" action="http://域名/项目/mpay/pay/gateway.do" method="post">
<input type="hidden" name="orderNo" value="888888"/><!--订单编号-->
<input type="hidden" name="type" value="weixin"/><!--支付类型-->
<input type="hidden" name="orderPrice" value="0.01"/>
<input type="hidden" name="orderDesc" value="铭飞商超系统"/>
<input type="text" name="authCode" value="45454XXXX3FF"/> <!--通过扫描枪扫码获取,可手动输入付款码底部对应的字符串-->
<input type="submit" value="确认">
</form>
2.5. 通用支付范例
通用支付页面,在服务器端封装页面需要的参数并渲染到支付页面,提高安全性
2.5.1. 前端自定义页面模板
...
<!--二维码-->
<div>
<qriously :value="wxCode" v-if="wxCode" :size="200"/>
</div>
<span class="pay-price">${pay.price}</span>
...
script
data: {
wxCode: "${pay.wxCode!''}",// 微信二维码
orderNo: "${pay.orderNo}",
},
methods:{
// 查询验证订单状态
checkOrder: function() {
var that = this
ms.http.get('/mpay/pay/status.do?orderNo=${pay.orderNo}').then(function(res) {
if(res.result && res.data == 'PAY') {
that.orderStatus = true;
clearInterval(that.listenerTimer)
}
})
},
}
2.5.2. 后端 封装页面需要的参数
// 业务对接支付接口
// 组装PayBean
PayBean pay = new PayBean();
pay.setOrderPrice("price"); // 价格
pay.setOrderNo("orderNo"); // 订单号
pay.setOrderName("orderName"); // 订单名称
pay.setOrderDesc("orderDesc"); // 订单描述
// xxxNotify需要实现IPayNotify接口 实现回调业务 params 自定义参数 具体查看本章扩展回调
pay.setAttach("{'notifyBeanName':'xxxNotify','params':"+params+"}");
pay.setReturnUrl(BasicUtil.getUrl()+"renwudating.html");
// payType 为空时默认微信支付
pay.setType(PayBean.Type.WEIXIN);
//微信支付,返回支付二维码
String wxCode = HttpUtil.post(BasicUtil.getUrl() + "/mpay/pay/gateway.do", BeanUtil.beanToMap(pay));
ResultData resultData = JSONUtil.toBean(wxCode, ResultData.class);
Map<String, Object> params = BasicUtil.assemblyRequestMap();
params.put("qrCode",resultData.getData(String.class));
// ... 其他需要在页面上渲染的参数
request.setAttribute("pay",params);
// 转发到自定义页面请求
return "forward:/xxx.do"
3. 发起退款
3.1. 业务方法关键类:
net.mingsoft.pay.biz.IPayLogBiz 关键方法:refund(....)
3.2. 范例
PayRefundBean payRefundBean = new PayRefundBean();
payRefundBean.setOrderNo("201908080808"); //订单号
payRefundBean.setType("WEI_XIN"); //支付宝支付:ALI_PAY 微信支付:WEI_XIN
payRefundBean.setPrice("8.8"); //退款费用
payRefundBean.setServiceCharge(0.5); //手续费
if(!net.mingsoft.pay.biz.IPayLogBiz.refund(payRefundBean){
System.out.print("退款失败");
} else {
System.out.print("退款成功");
// 流水交易为已退款
UpdateWrapper<PayLogEntity> wrapper = new UpdateWrapper<>();
wrapper.lambda().eq(PayLogEntity::getOrderNo,rewardedTask.getOrderNo()).set(PayLogEntity::getLogStatus,PayLogEntity.LogStatusEnum.REFUND);
payLogBiz.update(wrapper);
// 订单记录为已退款
···
}
注意在具体业务调用时退款同时要将订单状态和流水状态修改为已退款
除了bean形参的方法,还提供了一个重载方法形参为流水id范例如下
3.3. 范例
···
if(!net.mingsoft.pay.biz.IPayLogBiz.refund(payLogEntity.getId())){
System.out.print("退款失败");
} else {
System.out.print("退款成功");
// 订单记录为已退款
···
}