最近公司需要在现有的项目都加入微信支付。做了一个星期的微支付,就当分享一下自己所学到的一些知识吧。
JSAPI支付适用于手机版项目,当然也不是绝对的。流程大致:
1. 注册微信公众号(注册的时候注意选择公众号类型)
2. 公众号认证和微信支付认证(一般人工校验需要一天的时间)
3. 在微信公众号里授权微信支付url、OAuth2.0网页授权和JS接口安全授权(挺繁琐的= =)
4. 开发自己的支付代码
5. 测试、完成
步骤1和步骤2就不说了,这个已经和代码无关了。
接下来用图片说明步骤3:
1).授权微信支付URL:
步骤4(代码):
楼主也是参考”情本寂寞”这位大哥博客的,有兴趣的大家也可以看看哦^_^
首先来看微信开发文档的支付逻辑吧!
如图所示:
要获得用户的code这个参数,获取这个参数就需要调用微信的授权接口(https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect),当然咯这个接口就是跟我们上面设置的OAuth2.0网页授权有关,如果没有设置就获取不了openid的哦!APPID换成自己的公众号appid、REDIRECT_URI换成需要回调的链接咯、SCOPE如果不需要记录用户的信息只是想获取code的话就用snsapi_base就可以了。
//获取openid的方法
public String wxgetOpenid(){
String code = request.getParameter("code");
//ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code" 获取openid的微信接口
String urlstr = Constant.ACCESS_TOKEN.replace("APPID", Constant.APPID).replace("SECRET", Constant.APPSECRET).replace("CODE", code);
URL url;
url = new URL(urlstr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
// 取得输入流,并使用Reader读取
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));
String lines;
StringBuilder sb = new StringBuilder();
//接受返回的数据
while ((lines = reader.readLine()) != null) {
sb.append(lines);
}
reader.close();
// 断开连接
connection.disconnect();
//json对象需要json.org的jar包
JSONObject json;
//可以直接解析需要导入org.json.jar这个包哦
json = new JSONObject(sb.toString());
//目前只需要用到openid
openId = json.getString("openid");
//楼主保存openid的方法是用到session来保存的,不知道有没有更好的idea呢,可以分享出来哦
request.getSession().setAttribute("openid", openId);
return SUCCESS;
}
好咯,获取到openid之后就可以买东西,下订单,微信支付就可以等待快递收货了。哈哈
接下来讲在微信内置的浏览器里面调用微信支付JSAPI了
当用户买完商品之后进入选择页面点击支付发起JSPAI支付,如图:
当点击微信支付之后,就可以调用‘统一下单的接口’->获取返回的数据->调用JSPAI进行支付
我的思路是这样的:
首先利用ajax调用微信的‘统一下单接口’,然后获取一些支付需要的信息(可以查看微信支付文档),ajax获取到回调的信息之后,利用JSAPI发起微信支付。
1).微信统一下单接口获取支付订单数据:
/*
* 1.根据订单号查询订单信息
* 2.填写微信接口需要的订单信息
* 3.订单信息加密
* 4.封装成XML、调用微信接口
* 5.获取返回的值和需要的值封装成json返回到客户端
*/
订单信息就不用说了,接下来我用map格式封装微信统一下单接口需要的格式
SortedMap
map对应键的说明可以查看此表:
2).支付订单数据result封装成json格式用于ajax回调数据
//获取到返回值,解析成map格式
map = XMLMethods.doXMLParse(result);
//把返回的值变成json格式
SortedMap params = new TreeMap();
params.put("appId", Constant.APPID);
params.put("timeStamp", Long.toString(new Date().getTime()));
params.put("nonceStr", WXUtils.CreateNoncestr(32));
params.put("package", "prepay_id="+map.get("prepay_id"));
params.put("signType", Constant.SIGN_TYPE);
//注意paySign签名
String paySign = WXUtils.createSign("UTF-8", params);
//封装参数,前端调用微信支付
JSONObject json =new JSONObject();
json.put("appId", Constant.APPID);
json.put("timeStamp", params.get("timeStamp").toString());
json.put("nonceStr", params.get("nonceStr").toString());
json.put("package", "prepay_id="+map.get("prepay_id"));
json.put("signType", Constant.SIGN_TYPE);
json.put("paySign", paySign); //paySign的生成规则和Sign的生成规则一致
json.put("sendUrl", Constant.SUCCESS_URL); //付款成功后,点击完成跳转的页面
String userAgent = request.getHeader("user-agent"); //判断当前微信的版本
char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger")+15);
json.put("agent", new String(new char[]{agent})); //微信版本号,用于前面提到的判断用户手机微信的版本是否是5.0以上版本。
data = json.toString(); //这个data格式是要在前端调用的哦!大家可以注意一下
3).前端调用JSAPI进行支付
当获取到data数据之后就可以调用微信支付了(注意咯,调用微信支付的方法需要在当前页引入一个JS文件:),而调用这个文件也需要授权的哦,我们在上面第一步就已经授权了,就是在JS接口安全域名那里,大家还记得么?^_^。
WeixinJSBridge.invoke('getBrandWCPayRequest',{
"appId" : obj.appId, //公众号API
"timeStamp":obj.timeStamp, //时间戳,自 1970 年以来的秒数
"nonceStr" : obj.nonceStr, //随机串
"package" : obj.package, //商品包信息
"signType" : obj.signType, //微信签名方式
"paySign" : obj.paySign //微信签名
},function(res){
//当成功支付点击完成之后
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
//支付成功,处理成功的逻辑
location = obj.sendUrl;
}else{
//否则支付失败,处理失败的逻辑
alert("支付已取消");
}
});
4).支付成功,微信端回调函数
请看下图正确处理的逻辑
简单的一个回调代码如下:
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
String result = new String(outSteam.toByteArray(),"utf-8"); //获取微信调用我们notify_url的返回信息
Map map = XMLMethods.doXMLParse(result);
//支付成功
for(Object keyValue : map.keySet()){
System.out.println(keyValue+"="+map.get(keyValue));
}
//微信端已支付,处理订单业务
if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")){
//处理自己的业务逻辑
//发送信息给微信知道当前处理完业务逻辑、返回成功标识
response.getWriter().write(WXUtils.setXML("SUCCESS", "")); //告诉微信服务器,我收到信息了,不要在通知我了
}
总结:
其实不管是微信支付,支付宝支付等大致的思想都是差不多的。变得只是处理的数据细节需要变化(注意数据的并发行为)只要在逻辑上多留个心眼,保证支付的安全性这基本就OK了^_^。
里面的工具类可以在这里下载哦,大家可以参考一下。
博客可能存在很多错误,大家请多多包含,有错的地方可以留言告知,大家一起进步咯。嘻嘻!