关于微信支付初学者一定有很多的疑问,首先我们需要结合一下自己的程序操作微信支付所需要的业务流程。
1、如我这边需要开发一个公众号支付:
- 首先用户扫码访问后台(或者通过公众号直接进入,点击一个支付请求按钮)
- 后台处理(分析)请求的数据,返回处理结果给前端
- 前端需要显示处理结果(金额、商品信息、等….)并弹出微信支付输入密码
- 用户输入密码后,请求微信并返回支付结果(这里是微信帮我们完成的)
- 支付完成,微信会返回支付结果回调,到了这里我们可以处理支付的结果,比如修改数据库状态
- 可能用户后悔了,我们需要做微信退款(关于退款这边就不多说了)
2、开发流程:
(1)获取用户授权(分为静默授权 和 非静默授权两种)
这里我们需要两个参数分别是:APP_ID
这个我们在公众号上都能得到。
我们调用微信的接口获取授权
https://open.weixin.qq.com/connect/oauth2/authorize
需要的参数是:
appid(公众号上开发平台需要的唯一应用ID)、
redirect_uri(需要授权的页面地址,这里的这个地址是必须在公众号里填写并且是完整域名的)、
scope(snsapi_base为静默授权)
这里是我拼接完成的URL:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APP_ID
&redirect_uri=
URL地址
&response_type=code&scope=snsapi_base
&state=随意字符串
#wechat_redirect
接下来我们放到微信里面试一试吧!
静默授权我们看不到效果:吧scope改成【snsapi_userinfo
】
ps:静默授权会直接返回Code下面我们需要这个Code来做统一预支付接口
(2)调用统一下单接口获取预支付id这里需要在公众号开发平台做回调URL
这里会使用授权返回的Code来调用预支付接口
微信官方给了个参数的详细说明:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
后台处理逻辑我这边就不多做解释,只贴出关键代码,微信官方API文档,已经示例的Demo都有详细的注释。
我们需要建一个类存储交互必要的常量一遍以后使用
public class PayConfigUtil {
public static String APP_ID = "*******************";//微信开放平台应用ID
public static String APP_SECRET="*******************";//应用对应的凭证
public static String MCH_ID = "*******************";//商业号
public static String API_KEY = "*******************";//API key
public static String UFDODER_URL="*******************";//微信开发平台应用id
public static String NOTIFY_URL = "*******************";//回调地址
public static String CHARTSET = "UTF-8";//字符编码
}
//微信授权并发送订单
@RequestMapping(value="interface/weixin_pay")
@ResponseBody
public String weixin_pay(String money,String phone,String code,HttpServletResponse response,HttpServletRequest request) throws Exception {
Results results=new Results();
PrintWriter out =response.getWriter();
//金额转化为分为单位
String order_price =((int)((Double.parseDouble(money)) * 100)) + "";
String openid = getOpenId(code,PayConfigUtil.APP_ID,PayConfigUtil.API_KEY);
String currTime = PayCommonUtil.getCurrTime();
//8位日期
String strTime = currTime.substring(8, currTime.length());
//四位随机数
String strRandom =PayCommonUtil.buildRandom(4) + "";
//10位序列号,可以自行调整。
String strReq = strTime + strRandom;
String appid=PayConfigUtil.APP_ID;
//随机数
String nonce_str = strReq;
//商户订单号
String out_trade_no ="HZXY"+currTime+"WX"; //订单号
results.setTradeNo(out_trade_no);
//订单生成的机器 IP
String spbill_create_ip = request.getRemoteAddr();
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
packageParams.put("appid", PayConfigUtil.APP_ID);
packageParams.put("mch_id", PayConfigUtil.MCH_ID);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", phone);
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", order_price);
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", PayConfigUtil.NOTIFY_URL);
packageParams.put("trade_type", "JSAPI");
packageParams.put("openid", openid);
System.out.println("openid"+openid);
RequestHandler reqHandler = new RequestHandler(request, response);
reqHandler.init(appid, PayConfigUtil.APP_SECRET, PayConfigUtil.API_KEY);
String sign = reqHandler.createSign(packageParams);
packageParams.put("sign", sign);
System.out.println("aa"+sign);
String requestXML = PayCommonUtil.getRequestXml(packageParams);
String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);
Map map = XMLUtil.doXMLParse(resXml);
String prepay_id = (String) map.get("prepay_id");
String time=String.valueOf(System.currentTimeMillis() / 1000);
SortedMap<Object, Object> finalpackage = new TreeMap<Object, Object>();
String timestamp = time;
String packages = "prepay_id="+prepay_id;
finalpackage.put("appId", appid);
finalpackage.put("timeStamp", timestamp);
finalpackage.put("nonceStr", nonce_str);
finalpackage.put("package", packages);
finalpackage.put("signType", "MD5");
String paySign = reqHandler.createSign(finalpackage);
System.out.println("dd"+paySign);
results.setTimestamp(timestamp);
results.setNonceStr(nonce_str);
results.setPaySign(paySign);
results.setAppId(appid);
results.setOpenId(openid);
results.setPrepay_id(packages);
}else{
results.setEquipment("3");
}
out.print(JsonUtil.getJsonString4JavaPOJO(results));
return null;
}
这里微信官方的Api 有预支付参数的详细介绍这边就不多说了,我们这边主要存入金额,与用户授权成功之后返回的Code,
当然这个需要用户前端点击支付传递过来,后端解析完成,通过微信官方的API 生成xml报文,返回给前端处理
(3)前端页面使用微信支付内置的接收请求js
$.ajax({
cache: true,
type: "POST",
url:url,
data:{"type":type,"money":spans,"phone":phone,"code":code},// 你的formid
async: false,
success: function(res){
var obj = eval("("+res+")");
equipment=obj.equipment;
if(equipment=="1"){
window.location.href=obj.orderNumber;
}else if(equipment=="2"){
WeixinJSBridge.invoke('getBrandWCPayRequest',{
"appId" : obj.appId, //公众号名称,由商户传入
"timeStamp" : obj.timestamp, //时间戳,自 1970 年以来的秒数
"nonceStr" : obj.nonceStr, //随机串
"package" :obj.prepay_id, //商品包信息
"signType" : "MD5", //微信签名方式:
"paySign" : obj.sign //微信签名
},function(res) {
/* WeixinJSBridge.log(res.err_msg); */
if (res.err_msg == 'get_brand_wcpay_request:ok') {
if(status!=1){
window.location.href="index.jsp?qrCode="+cabinetNo;
}else{
window.location.href="index.jsp?qrCode="+cabinetNo;
}
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
window.location.href="index.jsp?qrCode="+cabinetNo;
} else {
}
});
}else if(equipment=="3"){
alert("当前手机号码不存在!");
}
},
error: function(res){
alert("请求失败!");
}
});
这里是输入正确的密码或者指纹验证完成,微信API会返回页面一个确认支付完成的页面,
而支付完成的页面跳转也在这边完成。
(4)支付完成后微信返回回调,后台处理结果
完成以上三个步骤之后 微信会返回一个回调给服务器。
就是前面配置的NOTIFY_URL ,这个地址必须是域名,并且在微信商户平台设置