申请微信支付在这里:https://blog.csdn.net/dmw412724/article/details/82735906
微信支付后台搭建(阅读本文的基础):https://blog.csdn.net/dmw412724/article/details/90053811
一。后台统一下单
private static Map<String, String> testOrder() throws Exception{
/**
* 统一下单所需数据
*/
Map<String, String> reqData = new HashMap<>();
reqData.put("out_trade_no", "101");
reqData.put("total_fee", "101");
reqData.put("notify_url", "http://www.baidu.com");
reqData.put("body", "请支付");
reqData.put("spbill_create_ip", "192.168.0.100");
reqData.put("openid", "oxaaaaaaaa");
reqData.put("trade_type", "JSAPI");
/**
* 发送请求
*/
WXPayConfigImpl config = new WXPayConfigImpl();//沙箱
WXPay pay = new WXPay(config);
Map<String, String> map = pay.unifiedOrder(reqData);
System.out.println(map);
/**
* 判断http成功且结果成功
*/
if ("SUCCESS".equals(map.get("return_code")) && "SUCCESS".equals(map.get("result_code"))){
Map<String, String> data = new HashMap<>();
//取出下面的值
data.put("appId", map.get("appid"));
data.put("timeStamp", Long.toString(WXPayUtil.getCurrentTimestamp()));
data.put("package", "prepay_id="+map.get("prepay_id"));//取出里面的预订单id
data.put("nonceStr", WXPayUtil.generateNonceStr());
data.put("signType", WXPayConstants.MD5);
//重新加密并塞到data里
data.put("paySign", WXPayUtil.generateSignature(data, config.getKey()));
return data;//把这个返回到前台
}
return null;
}
最终拿到数据应该得到了这几个东西:
appId,
timeStamp,
nonceStr,
package,
signType,
paySign
然后把这个map传递到前台就行了.因为这六个正好是前台所需要的
二. 前台
两种写法.一种是使用微信jssdk.一种是直接使用微信内置浏览器对象.它俩什么关系?应该是jssdk里引用了微信内置浏览器对象吧.
使用微信内置浏览器对象就意味着必须在微信里才能使用.这并不是在其他应用里唤醒微信并打开微信支付 .
1.jssdk写法.
这个是在使用jssdk需要进行初始化验签保证安全.这个大家都清楚.如果不懂,那么去看另外一种方法吧.
wx.config({
//debug: true,
appId: "",
timestamp: "",
nonceStr: "",
signature: "",
jsApiList: ["chooseWXPay"]
});
你还要引入一个js.微信的js
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
验完后调用这个就行了.
wx.chooseWXPay({
appId: data.body.appId,
timestamp: data.body.timeStamp,
nonceStr: data.body.nonceStr,
package: data.body.package,
signType: data.body.signType,
paySign: data.body.paySign,
success: function (res) {
alert("成功");
},
fail: function(res) {
alert('fail--'+JSON.stringify(res))
},
complete: function(res) {
alert('complete--'+JSON.stringify(res))
}
})
这个里面.data.body.xxx就是后台返回的值
不管怎样,都会走complete方法.
如果用户确认支付了,会走success方法.
如果调用api错误了.那么会走fail方法.
2.微信内置对象写法
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{
"appId":data.body.appId, //公众号名称,由商户传入
"timeStamp":data.body.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":data.body.nonceStr, //随机串
"package":data.body.package,
"signType":data.body.signType, //微信签名方式:
"paySign":data.body.paySign //微信签名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ){
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
}
);
这个里面.data.body.xxx就是上面那1.6里说的那个map里面的值.
3.一些返回fail的坑?
1.对于安卓来说,不管什么都是fail.所以请使用ios来调试,ios会告诉你到底怎么回事.
2.微信支付授权目录要配置正确(我目前是没有这个问题的).timeStamp是要大写的,但如果你用了我的工具类,也是不会出现这样的问题的..
3.客户端ip要真实.
4.如果使用jssdk写法.请引入jweixin-1.0.0.js
5.如果ios调试没有问题,而安卓有问题(或部分机型有问题?),那么你应该使用的是jssdk,你引入的那个jweixin-1.0.0.js放在了下面,应该把这条js放到最上面来引用.
三.回调
public String notifyUrlByWx(HttpServletRequest request) throws Exception {
String notifyData = WebUtils.getPostBody(request);//获取输入流xml字符串
Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); // 转换成map
if (WXPayUtil.isSignatureValid(notifyMap, WxPayConfig.KEY)) {
// 签名正确
// 进行处理。
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
String resultCode = notifyMap.get("result_code");
if (resultCode.equals("SUCCESS")){
//处理业务逻辑
//返回
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}else{
//如果支付失败
}
} else {
// 签名错误,如果数据里没有sign字段,也认为是签名错误
}
return "error";
}