走了不少的弯路,记录一下。
本博客借鉴自手把手教你–JAVA微信支付
尽信书,不如无书。
所需参数:
APPID(appid),APPSECEPT(appsecret),商户ID(mch_id),API密钥(paternerKey)
其他都好搞API密钥(paternerKey)进入商品平台操作下。
第一步:配置相关域名
1.进入商品平台设置授权目录:直接用一级域名即可
2.openid网页授权域名配置用于获取openid。
第二步:配置相关参数*
去官方下载例子
https://download.csdn.net/download/weixin_40927315/10855765
这里我打包好的一个积分,建议从官网下。
慢慢找的52个jar包
https://download.csdn.net/download/weixin_40927315/10856057
-
appid APPID (已有)
-
mch_id 商户ID (已有)
-
nonce_str 随机字符串
-
sign 签名
-
body 所支付的名称
-
out_trade_no 咱们自己所提供的订单号,需要唯一
-
total_fee 支付金额
-
spbill_create_ip IP地址
-
notify_url 回调地址
-
trade_type 支付类型
-
openid 支付人的微信公众号对应的唯一标识
3:随机字符串用WXPayUtil中的generateNonceStr()即可,就是生成UUID的方法
4:用WXPayUtil中的generateSignature(finalMap<String, String> data, String key)方法,data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)
8:用户端ip,估计就是用户点充值时的ip
String ip = req.getHeader("x-forwarded-for");
if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
ip = req.getHeader("Proxy-Client-IP");
}
if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
ip = req.getHeader("WL-Proxy-Client-IP");
}
if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
ip = req.getRemoteAddr();
}
if (ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
ip = ips[0].trim();
}
10:公众号支付此处给“JSAPI”
11.1:第一步:用户同意授权,获取code
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
注意:1. redirect_uri参数:授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理。
2. scope:用snsapi_base 。
这里的回调链接地址用于接收code,snsapi_base为静默授权
11.2
取得code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",//就是这个值
"scope":"SCOPE" }
这里这个授权access_token和全局调用那个不一样,这个可以无限调用,这个access_token也有时间,但是基本
上我去调用的时候都只用了几秒用来判断用户身份,这里应该可以搞个机制把它存下来,专用于获取openid,
但是这个access_token不是唯一的,每个用户一个,不能像全局调用那个一样去判断。
ok,参数都到位了!
post请求的方法,请求微信"统一下单接口https://api.mch.weixin.qq.com/pay/unifiedorder
发送前先用WXPayUtil工具类中的public static String mapToXml(Map<String,String> data)方法将有11个参数的map转成XML格式
然后你坚持到这里的话会看到这个:
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx2421b1c4370ec43b]]></appid>
<mch_id><![CDATA[10000100]]></mch_id>
<nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
<openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
<sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
<trade_type><![CDATA[JSAPI]]></trade_type>
</xml>
走到这里其实就为了得到prepay_id
!
第三步:支付
之前是预支付,现在可以用前端调用支付了。
首先:
1. appId:
2. timestamp:时间戳(newDate())
3. nonceStr:随机字符串,再次用WXPayUtil中的generateNonceStr();
4. package:”prepay_id=“+ prepay_id
5. signType:MD5
6. paySign:签名算法 ,用WXPayUtil中的publicstatic String generateSignature(final Map<String, String> data, Stringkey)方法,data是将除了paySign外,其他5个参数放到map中,keyAPI秘(paternerKey);
--------------------- -----------------------------------------------------------------------------------------------------------------------------
前端代码:
wx.config({
debug: false,
appId: "appId",
timestamp:"<%=timeStamp%>",
nonceStr:"<%=nonceStr%>",
signature:"<%=map.get("signature")%>",
jsApiList : ['chooseWXPay']
});//end_config
//步骤五
wx.error(function(res) {
alert("出错了:" + res.errMsg);
});
function onBridgeReady(){
wx.chooseWXPay({
"appId":"appId", //公众号名称,由商户传入
"timestamp":"<%=timeStamp%>", //时间戳,自1970年以来的秒数
"nonceStr":"<%=nonceStr%>", //随机串
"package":"<%=packages%>",
"signType":"MD5", //微信签名方式:
"paySign":"<%=paySign%>", //微信签名
success:function (res){
// 支付成功后的回调函数
alert("支付成功!");
window.location.href="回调地址";
},
//如果你按照正常的jQuery逻辑,下面如果发送错误,一定是error,那你就太天真了,当然,jssdk文档中也有提到
fail: function(res) {
//接口调用失败时执行的回调函数。
alert(res.errMsg);
},
complete: function(res) {
//接口调用完成时执行的回调函数,无论成功或失败都会执行。
},
cancel: function(res) {
//用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
},
trigger: function(res) {
//监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。
}
});
===================================================================================
注意此处:前面是微信接口配置参数,后面是支付接口参数。有人说这里的时间戳必须一样,经本人测试纯属谣言,这里够幸运的话点下确定,调用onBridgeReady()可以直接调出微信支付的界面!
一般来说,这里会签名错误,一定要反复检查签名和参数,尤其package,这个是包名,不能当变量!
**最后简单说下回调地址,这个地址非常重要,你只有看到回调成功才是真的成功,
然后你要在回调里做业务处理!*
/*****************微信回调返回数据样例*******************
$post = '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx2421b1c4370ec43b]]></appid>
<mch_id><![CDATA[10000100]]></mch_id>
<nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
<sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
<trade_type><![CDATA[APP]]></trade_type>
</xml>';
String wxNotifyXml = "";
try {
DataInputStream in = new DataInputStream(req.getInputStream());
byte[] dataOrigin = new byte[req.getContentLength()];
in.readFully(dataOrigin);
if (in != null) in.close();
wxNotifyXml = new String(dataOrigin);
} catch (IOException e) {
e.printStackTrace();
}
Map notifyMap = WXPayUtil.xmlToMap(wxNotifyXml);
String openid =(String)notifyMap.get("openid");
if ((((String)notifyMap.get("return_code")).equals("SUCCESS")) &&
(((String)notifyMap.get("result_code")).equals("SUCCESS"))) {
//业务处理代码
}