在没做过微信支付时感觉被微信支付搞到头都大了,但是当真的理解了后就感觉很简单其实就是带参数发请求,没做过支付肯定看不懂微信支付官方文档的流程图,看完一脸闷。。。
下面在这里说下流程
1:当用户发起支付请求时在我们自己的后台拼接好必要的参数发送给微信。(生成预支付订单)
1.1:参数(主要参数)
(1)appid:公众号或者小程序的appid
(2)mch_id: 商户号id
(3)nonce_str: 随即字符串
(4)body: 商品描述
(5)out_trade_no: 商户订单号
(6)total_fee: 总金额(注意:以分为单位)
(7)spbill_create_ip: 终端IP
(8)notify_url: 通知地址:回调函数
(9)trade_type: 交易类型
(10)openid: 用户的openid,在网页支付等不需要
(11)sign: 签名
2:微信返回给我们一些前段调起支付必要的参数
2.1参数(主要参数)
(1)appid:公众号或者小程序的appid
(2)mch_id: 商户号id
(3)nonce_str: 随机字符串
(4)sign: 签名
(5)result_code: 业务结果
(6)trade_type: 交易类型
(7)prepay_id: 预支付交易会话标识
3:返回的参数如果是公众号或者小程序支付需要把一些参数再次加密,返回给前台调取支付,否则前段会显示签名错误。
4:用户支付完成后微信回调notify_url所配置的地址(注意:回调处理完成后不管成功或失败一定要给微信返回成功或失败的通知,否则微信会多次回调)。
5:好了流程说完了现在开始上代码。(注意:我是为了演示所以返回的是Map,请根据需求自行返回,下面的参数都是我乱写的请改成自己所需要的)
public static Map<String, Object> wxPay() {
String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
// 调微信下单接口
StringBuffer param = new StringBuffer();
param.append("<xml>");
param.append("<appid>xxxxxxxxx</appid>");//换成自己的公众号或小程序的appid
param.append("<mch_id>xxxxxxxxx</mch_id>");//换成自己的商户号id
param.append("<nonce_str>" + nonceStr + "</nonce_str>");
param.append("<body>我来测试下</body>");// 商品描述
param.append("<out_trade_no>2019012322987654</out_trade_no>");// 换成自己商户订单号
param.append("<total_fee>1</total_fee>");// 换成自己总金额
param.append("<spbill_create_ip>192.101.0.1</spbill_create_ip>");// 换成自己终端IP
param.append("<notify_url>http:xxx.cn/xxx</notify_url>");// 换成自己通知地址:回调函数
param.append("<trade_type>JSAPI</trade_type>");// 交易类型
param.append("<openid>xxxxxxxxxxxxxxxxx</openid>");// 换成自己openid
String noncestr = "appid=xxxxxxxxx"//这下面的参数就是上面的参数请务必保持一致
+ "&body=我来测试下"
+ "&mch_id=xxxxxxxxx"
+ "&nonce_str=" + nonceStr
+ "¬ify_url=http:xxx.cn/xxx"
+ "&openid=xxxxxxxxxxxxxxxxx"
+ "&out_trade_no=2019012322987654"
+ "&spbill_create_ip=192.101.0.1"
+ "&total_fee=1"
+ "&trade_type=JSAPI"
+ "&key=xxxxxxxxxxxxxxxxxxxxxxxx";//换上自己的商户号
String md5Encode = MD5.MD5Encode(noncestr);
param.append("<sign>" + md5Encode + "</sign>");
param.append("</xml>");
String result = HttpUrlUtil.sendPost(
"https://api.mch.weixin.qq.com/pay/unifiedorder",
param.toString());
System.out.println(new String(result.getBytes(), "UTF-8"));
String return_code = null;
String return_msg = null;
String result_code = null;
String appid = null;
String mch_id = null;
String nonceStr = sb.toString();
String prepay_id = null;
String timeStamp = (System.currentTimeMillis() / 1000) + "";
String signType = "MD5";
signType = new String(signType.getBytes(), "UTF-8");
String paySign = null;
Document doc = DocumentHelper.parseText(result); // 将字符串转为XML
Element node = doc.getRootElement(); // 获取根节点
List<Element> listElement = node.elements();// 所有一级子节点的list
for (Element e : listElement) {// 遍历所有一级子节点
if (e.getName().equals("return_code")) {
return_code = e.getTextTrim();
} else if (e.getName().equals("return_msg")) {
return_msg = e.getTextTrim();
} else if (e.getName().equals("result_code")) {
result_code = e.getTextTrim();
} else if (e.getName().equals("prepay_id")) {
prepay_id = "prepay_id=" + e.getTextTrim();
} else if (e.getName().equals("appid")) {
appid = e.getTextTrim();
} else if (e.getName().equals("mch_id")) {
mch_id = e.getTextTrim();
}
}
Map<String, Object> map = new HashMap<String, Object>();
if (result_code.equals("SUCCESS")) {
// 再次签名用于小程序调用支付
String pay = "appId=" + appid + "&nonceStr=" + nonceStr
+ "&package=" + prepay_id + "&signType=" + signType
+ "&timeStamp=" + timeStamp
+ "&key=xxxxxxxxxxxxxxxxxxxxxxxx";//换上自己的商户号
String md5EncodeXCX = MD5.MD5Encode(pay);
// 微信返回数据返回给小程序调取支付
map.put("nonceStr", nonceStr);
map.put("package", prepay_id);
map.put("timeStamp", timeStamp);
map.put("signType", signType);
map.put("appId", appid);
map.put("paySign", md5EncodeXCX);
map.put("order", orderId);
} else {
throw new Exception("操作失败");
}
return map;
}
6:参数这样就到了前台了由于写的是小程序或公众号的支付所以只列举这两个
6.1:公众号(注意:把对应的参数放上去)
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": xxx, //公众号名称,由商户传入
"timeStamp": xxx, //时间戳,自1970年以来的秒数
"nonceStr": xxx, //随机串
"package": xxx, //统一订单号
"signType": xxx, //微信签名方式:
"paySign": xxx //支付签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
alert("支付成功");
}// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
if (res.err_msg == "get_brand_wcpay_request:cancel") {
alert("支付取消");
}
if (res.err_msg == "get_brand_wcpay_request:fail") {
alert("支付失败");
}
}
);
6.2:公众号支付(注意:把对应的参数放上去)
wx.requestPayment({
'timeStamp': xxx,
'nonceStr': xxx,
'package': xxx,
'signType': xxx,
'paySign': xxx,
'success': function (res) {
},
'fail': function (res) {
}
})
7:支付回调
private String Xxx(HttpServletRequest req, HttpServletResponse resp) throws IOException {
java.io.BufferedInputStream bis = new java.io.BufferedInputStream(
req.getInputStream());
byte read[] = new byte[1024 * 1024];
String loc = "";
try {
while ((bis.read(read, 0, 1 * 1)) != -1) {
loc += new String(read, 0, 1 * 1);
}
String total_fee = null;// 标价金额
String result_code = null;// 业务结果
String return_code = null;// 返回状态码
String time_end = null;// 支付完成时间
String is_subscribe = null;// 是否关注公众账号
String out_trade_no = null;// 商户订单号
Document doc = DocumentHelper.parseText(loc);// 将字符串转为XML
Element root = doc.getRootElement();// 获取根元素
List<Element> list1 = root.elements();
for (Element e : list1) {
if (e.getName().equals("total_fee")) {
total_fee = e.getTextTrim();
} else if (e.getName().equals("result_code")) {
result_code = e.getTextTrim();
} else if (e.getName().equals("return_code")) {
return_code = e.getTextTrim();
} else if (e.getName().equals("time_end")) {
time_end = e.getTextTrim();
} else if (e.getName().equals("is_subscribe")) {
is_subscribe = e.getTextTrim();
} else if (e.getName().equals("out_trade_no")) {
out_trade_no = e.getTextTrim();
}
}
PrintWriter out = resp.getWriter();
if (result_code.equals("SUCCESS") && return_code.equals("SUCCESS")) {// 支付成功
//这里写自己的业务
//返回给微信
resXml = "<xml>"
+ "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
resXml = new String(resXml.getBytes(), "UTF-8");
} else {
resXml = "<xml>"
+ "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[订单已存在或金额错误]]></return_msg>"
+ "</xml> ";
resXml = new String(resXml.getBytes(), "UTF-8");
}
} catch (DocumentException e) {
e.printStackTrace();
} finally {
transaction = null;// 释放资源
bis.close();
}
// 通知微信服务器已经支付成功
resp.getWriter().write(resXml);
return resXml;
}
好了至此微信支付流程完成。
PS:有人今天弄好了支付,明天就不行了报签名错误,请更换商户秘钥再次尝试